From 12ed7a679dfd7ad70912e0197348fc848348090c Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 24 Nov 2015 15:39:39 +0200 Subject: [PATCH 01/66] mixer code --- .../src/main/proto/meerkat/mixing.proto | 42 +++- mixer/build.gradle | 205 ++++++++++++++++++ mixer/src/main/java/mixer/Graph.java | 100 +++++++++ mixer/src/main/java/mixer/Mixer.java | 172 +++++++++++++++ settings.gradle | 1 + 5 files changed, 518 insertions(+), 2 deletions(-) create mode 100644 mixer/build.gradle create mode 100644 mixer/src/main/java/mixer/Graph.java create mode 100644 mixer/src/main/java/mixer/Mixer.java diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 50cffc7..8adade9 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -6,7 +6,45 @@ option java_package = "meerkat.protobuf"; import 'meerkat/crypto.proto'; -// TODO: message ZeroKnowledgeProof { bytes data = 1; -} \ No newline at end of file +} + +//message ZeroKnowledgeProof { +// +// message OrProof{ +// message GroupMember{ +// required bytes data = 1; +// } +// message BigIntegerMsg{ +// required bytes data = 1; +// } +// //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; +// required GroupMember g1 = 1; +// required GroupMember h1 = 2; +// required GroupMember g2 = 3; +// required GroupMember h2 = 4; +// required GroupMember g1Tag = 5; +// required GroupMember h1Tag = 6; +// required GroupMember g2Tag = 7; +// required GroupMember h2Tag = 8; +// +// //calc: u, v, uTag, vTag; +// required GroupMember g2 = 9; +// required GroupMember h2 = 10; +// required GroupMember g1Tag = 11; +// required GroupMember h1Tag = 12; +// +// //generated: c1,c2,z,zTag +// required BigIntegerMsg c1 = 13; +// required BigIntegerMsg c2 = 14; +// required BigIntegerMsg z = 15; +// required BigIntegerMsg zTag = 16; +// } +// +// required OrProof first = 1; +// required OrProof second = 2; +// required OrProof third = 3; +// required OrProof fourth = 4; +//} +// \ No newline at end of file diff --git a/mixer/build.gradle b/mixer/build.gradle new file mode 100644 index 0000000..14cb9dd --- /dev/null +++ b/mixer/build.gradle @@ -0,0 +1,205 @@ + +plugins { + id "us.kirchmeier.capsule" version "1.0.1" + id 'com.google.protobuf' version '0.7.0' +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'idea' + +apply plugin: 'maven-publish' + +// Uncomment the lines below to define an application +// (this will also allow you to build a "fatCapsule" which includes +// the entire application, including all dependencies in a single jar) +//apply plugin: 'application' +//mainClassName='your.main.ApplicationClass' + +// Is this a snapshot version? +ext { isSnapshot = false } + +ext { + groupId = 'org.factcenter.meerkat' + nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/" + + // Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing) + // Should be set in ${HOME}/.gradle/gradle.properties + nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : "" + nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" +} + +description = "TODO: Add a description" + +// Your project version +version = "0.0" + +version += "${isSnapshot ? '-SNAPSHOT' : ''}" + + +dependencies { + // Meerkat common + compile project(':meerkat-common') + + // Logging + compile 'org.slf4j:slf4j-api:1.7.7' + runtime 'ch.qos.logback:logback-classic:1.1.2' + runtime 'ch.qos.logback:logback-core:1.1.2' + + // Google protobufs + compile 'com.google.protobuf:protobuf-java:3.+' + + testCompile 'junit:junit:4.+' + + runtime 'org.codehaus.groovy:groovy:2.4.+' +} + + +/*==== You probably don't have to edit below this line =======*/ + +// The run task added by the application plugin +// is also of type JavaExec. +tasks.withType(JavaExec) { + // Assign all Java system properties from + // the command line to the JavaExec task. + systemProperties System.properties +} + + +protobuf { + // Configure the protoc executable + protoc { + // Download from repositories + artifact = 'com.google.protobuf:protoc:3.+' + } +} + + +idea { + module { + project.sourceSets.each { sourceSet -> + + def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" + + println "Adding $srcDir" + // add protobuf generated sources to generated source dir. + if ("test".equals(sourceSet.name)) { + testSourceDirs += file(srcDir) + } else { + sourceDirs += file(srcDir) + } + generatedSourceDirs += file(srcDir) + + } + + // Don't exclude build directory + excludeDirs -= file(buildDir) + } +} + + +/*=================================== + * "Fat" Build targets + *===================================*/ + + +if (project.hasProperty('mainClassName') && (mainClassName != null)) { + + task mavenCapsule(type: MavenCapsule) { + description = "Generate a capsule jar that automatically downloads and caches dependencies when run." + applicationClass mainClassName + destinationDir = buildDir + } + + task fatCapsule(type: FatCapsule) { + description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class" + + destinationDir = buildDir + + def fatMain = hasProperty('fatmain') ? fatmain : mainClassName + + applicationClass fatMain + + def testJar = hasProperty('test') + + if (hasProperty('fatmain')) { + appendix = "fat-${fatMain}" + } else { + appendix = "fat" + } + + if (testJar) { + from sourceSets.test.output + } + } +} + + +/*=================================== + * Repositories + *===================================*/ + +repositories { + + // Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral) + maven { + url nexusRepository + + if (isSnapshot) { + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } + + // Use local maven repository + mavenLocal() + + // Use 'maven central' for other dependencies. + mavenCentral() +} + +task "info" << { + println "Project: ${project.name}" +println "Description: ${project.description}" + println "--------------------------" + println "GroupId: $groupId" + println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})" + println "" +} +info.description 'Print some information about project parameters' + + +/*=================================== + * Publishing + *===================================*/ + +publishing { + publications { + mavenJava(MavenPublication) { + groupId project.groupId + pom.withXml { + asNode().appendNode('description', project.description) + } + from project.components.java + + } + } + repositories { + maven { + url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}" + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } +} + + + diff --git a/mixer/src/main/java/mixer/Graph.java b/mixer/src/main/java/mixer/Graph.java new file mode 100644 index 0000000..b600be8 --- /dev/null +++ b/mixer/src/main/java/mixer/Graph.java @@ -0,0 +1,100 @@ +package mixer; + +import java.util.ArrayList; +import java.util.List; + +class Graph +{ + private int n; + private Node[] nodes; + protected Graph(int[] permutation){ + n = permutation.length; // n = 2^k + createNodes(); + createEdges(permutation); + setSwitches(); + } + + protected boolean getSwitchValue(int index,boolean up) + { + // index must be less then n/2 + return up ? nodes[index].on : nodes[index + n / 2].on; + } + + private void createNodes() + { + nodes = new Node[n]; + for (int i = 0; i < n / 2; i++) + { + nodes[i] = new Node(i, i + n / 2, true); + nodes[i + n / 2] = new Node(i, i + n / 2, false); + } + } + + private void createEdges(int[] permutation) + { + int pi1, pi2; + for (int i = 0; i < n / 2; i++) + { + pi1 = (permutation[i] < n / 2) ? permutation[i] + (n / 2) : permutation[i]; + pi2 = (permutation[i + n / 2] < n / 2) ? permutation[i + n / 2] + (n / 2) : permutation[i + n / 2]; + + nodes[i].edges.add(new Edge(nodes[pi1], (permutation[i] >= n / 2))); + nodes[pi1].edges.add(new Edge(nodes[i], (permutation[i] >= n / 2))); + + nodes[i].edges.add(new Edge(nodes[pi2], (permutation[i + n / 2] < n / 2))); + nodes[pi2].edges.add(new Edge(nodes[i], (permutation[i + n / 2] < n / 2))); + } + } + + private void setSwitches() + { + for (int i = 0; i < n / 2; i++) + { + Node node = nodes[i]; + if (node.set) + continue; + boolean v = false; + while (true) + { + node.set = true; + node.on = v; + + if (node.edges.get(0).nighbor.set && node.edges.get(1).nighbor.set) + break; + v ^= (!node.edges.get(0).nighbor.set) ? node.edges.get(0).broken : node.edges.get(1).broken; + node = (!node.edges.get(0).nighbor.set) ? node.edges.get(0).nighbor : node.edges.get(1).nighbor; + } + } + } + + private class Node + { + public boolean up; + public List edges; + public int i, j; + public boolean on; + public boolean set; + public Node(int i, int j,boolean up) + { + this.i = i; + this.j = j; + this.up = up; + edges = new ArrayList(); + set = false; + } + } + + private class Edge + { + public Node nighbor; + public boolean broken; + public Edge(Node nighbor, boolean broken) + { + this.nighbor = nighbor; + this.broken = broken; + } + } + + +} + diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java new file mode 100644 index 0000000..c4d2952 --- /dev/null +++ b/mixer/src/main/java/mixer/Mixer.java @@ -0,0 +1,172 @@ +package mixer; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +import com.google.protobuf.InvalidProtocolBufferException; + +import javafx.util.Pair; + +import java.util.Random; + +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Mixing.*; + +import meerkat.crypto.Encryption; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; + +public class Mixer{ + + private Random random; + private Mix2ZeroKnowledgeProver prover; + private Encryption encryptor; + + public Mixer(Random rand,Mix2ZeroKnowledgeProver prov,Encryption enc) { + this.random = rand; + this.prover = prov; + this.encryptor = enc; + + } + + public Pair mix(List ciphertexts) throws InvalidProtocolBufferException{ + + int n = ciphertexts.size(); + // assert n = 2^k and n > 1 + if( n <= 1 || ((n & (n-1)) != 0)) + return null; + + //initialization + int layers = 0; + for (int i = n; i > 1; i>>=1) { + layers++; + } + layers<<=1; + layers--; + RerandomizableEncryptedMessage[][] encryptionsTable = new RerandomizableEncryptedMessage[layers][n]; + ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2]; + boolean[][] mixnet = createMixNet(n,layers); + int index1, index2, switchIndex = 0; + EncryptionRandomness r1 ,r2; + RerandomizableEncryptedMessage e1, e2; + boolean half = true; + + //set first level of encryptions + for (int j = 0; j < n; j++) + { + encryptionsTable[0][j] = ciphertexts.get(j); + } + + // main loop + for (int i = n, layer = 0; layer < layers; layer++) // i == permutation size + { + for (int j = 0; j < n; j += i) // + { + for (int k = 0; k < i / 2; k++) + { + index1 = k + j; + index2 = k + j + i / 2; + e1 = encryptionsTable[layer][index1]; + e2 = encryptionsTable[layer][index2]; + r1 = encryptor.generateRandomness(random); + r2 = encryptor.generateRandomness(random); + if (!mixnet[layer][switchIndex]) + { + encryptionsTable[layer+1][index1] = encryptor.rerandomize(e1, r1); + encryptionsTable[layer+1][index2] = encryptor.rerandomize(e2,r2); + + } + else + { + encryptionsTable[layer+1][index1] = encryptor.rerandomize(e2,r2); + encryptionsTable[layer+1][index2] = encryptor.rerandomize(e1,r1); + } + proofsTable[layer][switchIndex] = + prover.prove(e1, e2, encryptionsTable[layer + 1][index1], + encryptionsTable[layer + 1][index2], + mixnet[layer][switchIndex], r1,r2); + + switchIndex = (switchIndex + 1) % (n / 2); + } + } + if (half) + { + i >>= 1; + if (i == 1) + { + half = false; + i = 4; + } + } + else + { + i <<= 1; + } + } + return new Pair(proofsTable, encryptionsTable); + } + + private int[] randomPermutation(int n){ + List numbers= new ArrayList(n); + for (int i = 0; i < n; i++) + { + numbers.add(i); + } + + int[] result = new int[n]; + int index; + for (int i = 0; i < n; i++) + { + index = random.nextInt(n - i); + result[i] = numbers.get(index); + numbers.remove(index); + } + return result; + } + + private boolean[][] createMixNet(int n,int layers) + { + int[] permutaion = randomPermutation(n); + int[] pi, piL, piR; + Queue permutaions = new ArrayBlockingQueue(n); + Graph graph; + boolean[][] mixnet = new boolean[layers][n>>1]; + + permutaions.add(permutaion); + + for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size + { + for (int j = 0; j < n / 2; j += i / 2) // + { + pi = permutaions.remove(); + graph = new Graph(pi); + piL = new int[i / 2]; + piR = new int[i / 2]; + for (int k = 0; k < i / 2; k++) + { + mixnet[layers - layer - 1][k + j] = graph.getSwitchValue(k, true); + mixnet[layer][k + j] = graph.getSwitchValue(k, false); + + if (!mixnet[layers - layer - 1][k + j]) + { + piL[k] = pi[k] % (i / 2); + piR[k] = pi[k + i / 2] % (i / 2); + } + else + { + piL[k] = pi[k + i / 2] % (i / 2); + piR[k] = pi[k] % (i / 2); + } + } + permutaions.add(piL); + permutaions.add(piR); + } + } + return mixnet; + } + +} diff --git a/settings.gradle b/settings.gradle index e4ef054..043ce64 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,3 +3,4 @@ include 'voting-booth' include 'bulletin-board-server' include 'polling-station' include 'restful-api-common' +include 'mixer' \ No newline at end of file From a834194d504d15c3e6ee95d202a3289305a7d58f Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 1 Dec 2015 21:48:41 +0200 Subject: [PATCH 02/66] mixer project --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/meerkat/crypto/mixnet/Mixer.java | 7 +- .../src/main/proto/meerkat/mixing.proto | 74 ++++++++--------- mixer/src/main/java/mixer/Graph.java | 80 ++++++++++++------- mixer/src/main/java/mixer/Mixer.java | 71 ++++++++-------- 5 files changed, 122 insertions(+), 112 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7b65bea..3555c28 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Mon Oct 26 15:30:44 IST 2015 +#Tue Dec 01 01:04:39 IST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 52e8844..bbd999e 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -1,5 +1,10 @@ package meerkat.crypto.mixnet; +import com.google.protobuf.InvalidProtocolBufferException; +import javafx.util.Pair; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + import java.util.List; import static meerkat.protobuf.Voting.*; @@ -7,5 +12,5 @@ import static meerkat.protobuf.Voting.*; * Created by talm on 25/10/15. */ public interface Mixer { - public List mix(List ballots); + public Pair mix(List ciphertexts) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 8adade9..8e56e2e 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -7,44 +7,38 @@ option java_package = "meerkat.protobuf"; import 'meerkat/crypto.proto'; message ZeroKnowledgeProof { - bytes data = 1; -} + message OrProof { + message GroupMember { + bytes data = 1; + } + message BigIntegerMsg { + bytes data = 1; + } -//message ZeroKnowledgeProof { -// -// message OrProof{ -// message GroupMember{ -// required bytes data = 1; -// } -// message BigIntegerMsg{ -// required bytes data = 1; -// } -// //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; -// required GroupMember g1 = 1; -// required GroupMember h1 = 2; -// required GroupMember g2 = 3; -// required GroupMember h2 = 4; -// required GroupMember g1Tag = 5; -// required GroupMember h1Tag = 6; -// required GroupMember g2Tag = 7; -// required GroupMember h2Tag = 8; -// -// //calc: u, v, uTag, vTag; -// required GroupMember g2 = 9; -// required GroupMember h2 = 10; -// required GroupMember g1Tag = 11; -// required GroupMember h1Tag = 12; -// -// //generated: c1,c2,z,zTag -// required BigIntegerMsg c1 = 13; -// required BigIntegerMsg c2 = 14; -// required BigIntegerMsg z = 15; -// required BigIntegerMsg zTag = 16; -// } -// -// required OrProof first = 1; -// required OrProof second = 2; -// required OrProof third = 3; -// required OrProof fourth = 4; -//} -// \ No newline at end of file + //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; + GroupMember g1 = 1; + GroupMember h1 = 2; + GroupMember g2 = 3; + GroupMember h2 = 4; + GroupMember g1Tag = 5; + GroupMember h1Tag = 6; + GroupMember g2Tag = 7; + GroupMember h2Tag = 8; + + //calc: u, v, uTag, vTag; + GroupMember u = 9; + GroupMember v = 10; + GroupMember uTag = 11; + GroupMember vTag = 12; + + //generated: c1,c2,z,zTag + BigIntegerMsg c1 = 13; + BigIntegerMsg c2 = 14; + BigIntegerMsg z = 15; + BigIntegerMsg zTag = 16; + } + OrProof first = 1; + OrProof second = 2; + OrProof third = 3; + OrProof fourth = 4; +} diff --git a/mixer/src/main/java/mixer/Graph.java b/mixer/src/main/java/mixer/Graph.java index b600be8..d57a044 100644 --- a/mixer/src/main/java/mixer/Graph.java +++ b/mixer/src/main/java/mixer/Graph.java @@ -6,78 +6,96 @@ import java.util.List; class Graph { private int n; + private int nDiv2; private Node[] nodes; protected Graph(int[] permutation){ n = permutation.length; // n = 2^k + nDiv2 = n /2; createNodes(); createEdges(permutation); setSwitches(); } - + + // provide an access to graph to algorithm result + // index must be less then n/2 protected boolean getSwitchValue(int index,boolean up) { - // index must be less then n/2 return up ? nodes[index].on : nodes[index + n / 2].on; } - + + // create two lines of nodes size n/2 each + // the value of the i th node is (i,i+n/2) if i < n /2 (first line) + // otherwise its value is (i - n/2 , i) (second line) private void createNodes() { nodes = new Node[n]; for (int i = 0; i < n / 2; i++) { - nodes[i] = new Node(i, i + n / 2, true); - nodes[i + n / 2] = new Node(i, i + n / 2, false); + nodes[i] = new Node(true); + nodes[i + nDiv2] = new Node(false); } } - + + // create an edge between each pair of nodes i,j from different lines (i index of the first line) + // if exists k in i th node's value and t in j th node's value + // s.t permutation[k] == t + // the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) + // Note: in purpose to avoid edge cases, each node has exactly two edges private void createEdges(int[] permutation) { - int pi1, pi2; - for (int i = 0; i < n / 2; i++) + int j; + for (int i = 0; i < nDiv2; i++) { - pi1 = (permutation[i] < n / 2) ? permutation[i] + (n / 2) : permutation[i]; - pi2 = (permutation[i + n / 2] < n / 2) ? permutation[i + n / 2] + (n / 2) : permutation[i + n / 2]; + j = (permutation[i] % nDiv2) + nDiv2; + nodes[i].edges.add(new Edge(nodes[j], (permutation[i] >= nDiv2))); + nodes[j].edges.add(new Edge(nodes[i], (permutation[i] >= nDiv2))); - nodes[i].edges.add(new Edge(nodes[pi1], (permutation[i] >= n / 2))); - nodes[pi1].edges.add(new Edge(nodes[i], (permutation[i] >= n / 2))); - - nodes[i].edges.add(new Edge(nodes[pi2], (permutation[i + n / 2] < n / 2))); - nodes[pi2].edges.add(new Edge(nodes[i], (permutation[i + n / 2] < n / 2))); + j = (permutation[i + nDiv2] % nDiv2) + nDiv2; + nodes[i].edges.add(new Edge(nodes[j], (permutation[i + nDiv2] < nDiv2))); + nodes[j].edges.add(new Edge(nodes[i], (permutation[i + nDiv2] < nDiv2))); } } - + + // set switch's value (on/off) for each switch (node) + // s.t if nodes i,j connected by edge e, i th switch's value + // must be equal to j's if e is broken or not equal if e is not broken private void setSwitches() { - for (int i = 0; i < n / 2; i++) + Node node; + boolean v; + Edge e0,e1; + // iterate over first line of nodes + for (int i = 0; i < nDiv2; i++) { - Node node = nodes[i]; + node = nodes[i]; if (node.set) continue; - boolean v = false; + //select default value for first node in connected component + v = false; + // set value to all reachable nodes from node while (true) { node.set = true; node.on = v; - - if (node.edges.get(0).nighbor.set && node.edges.get(1).nighbor.set) + e0 = node.edges.get(0); e1 = node.edges.get(1); + if (e0.neighbor.set && e1.neighbor.set) break; - v ^= (!node.edges.get(0).nighbor.set) ? node.edges.get(0).broken : node.edges.get(1).broken; - node = (!node.edges.get(0).nighbor.set) ? node.edges.get(0).nighbor : node.edges.get(1).nighbor; + v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; + node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; } } } - + + //inner classes + private class Node { public boolean up; public List edges; - public int i, j; public boolean on; public boolean set; - public Node(int i, int j,boolean up) + public Node(boolean up) { - this.i = i; - this.j = j; this.up = up; edges = new ArrayList(); set = false; @@ -86,11 +104,11 @@ class Graph private class Edge { - public Node nighbor; + public Node neighbor; public boolean broken; - public Edge(Node nighbor, boolean broken) + public Edge(Node neighbor, boolean broken) { - this.nighbor = nighbor; + this.neighbor = neighbor; this.broken = broken; } } diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index c4d2952..e8fee4b 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -1,26 +1,20 @@ package mixer; -import java.math.BigInteger; import java.util.ArrayList; -import java.util.Dictionary; import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; - -import com.google.protobuf.InvalidProtocolBufferException; - import javafx.util.Pair; - import java.util.Random; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Mixing.*; import meerkat.crypto.Encryption; -import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -public class Mixer{ +public class Mixer implements meerkat.crypto.mixnet.Mixer{ private Random random; private Mix2ZeroKnowledgeProver prover; @@ -34,7 +28,7 @@ public class Mixer{ } public Pair mix(List ciphertexts) throws InvalidProtocolBufferException{ - + int n = ciphertexts.size(); // assert n = 2^k and n > 1 if( n <= 1 || ((n & (n-1)) != 0)) @@ -47,7 +41,7 @@ public class Mixer{ } layers<<=1; layers--; - RerandomizableEncryptedMessage[][] encryptionsTable = new RerandomizableEncryptedMessage[layers][n]; + RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers][n]; ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2]; boolean[][] mixnet = createMixNet(n,layers); int index1, index2, switchIndex = 0; @@ -55,39 +49,40 @@ public class Mixer{ RerandomizableEncryptedMessage e1, e2; boolean half = true; - //set first level of encryptions + //set first level of encryption for (int j = 0; j < n; j++) { - encryptionsTable[0][j] = ciphertexts.get(j); + encryptionTable[0][j] = ciphertexts.get(j); } - // main loop - for (int i = n, layer = 0; layer < layers; layer++) // i == permutation size + // main loop + int i = n; + for (int layer = 0; layer < layers; layer++) // i == permutation size { - for (int j = 0; j < n; j += i) // + for (int j = 0; j < n; j += i) // j == permutation index { - for (int k = 0; k < i / 2; k++) + for (int k = 0; k < i / 2; k++) // k == elements index in permutation j { index1 = k + j; index2 = k + j + i / 2; - e1 = encryptionsTable[layer][index1]; - e2 = encryptionsTable[layer][index2]; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; r1 = encryptor.generateRandomness(random); r2 = encryptor.generateRandomness(random); if (!mixnet[layer][switchIndex]) { - encryptionsTable[layer+1][index1] = encryptor.rerandomize(e1, r1); - encryptionsTable[layer+1][index2] = encryptor.rerandomize(e2,r2); + encryptionTable[layer+1][index1] = encryptor.rerandomize(e1, r1); + encryptionTable[layer+1][index2] = encryptor.rerandomize(e2,r2); } else { - encryptionsTable[layer+1][index1] = encryptor.rerandomize(e2,r2); - encryptionsTable[layer+1][index2] = encryptor.rerandomize(e1,r1); + encryptionTable[layer+1][index1] = encryptor.rerandomize(e2,r2); + encryptionTable[layer+1][index2] = encryptor.rerandomize(e1,r1); } proofsTable[layer][switchIndex] = - prover.prove(e1, e2, encryptionsTable[layer + 1][index1], - encryptionsTable[layer + 1][index2], + prover.prove(e1, e2, encryptionTable[layer + 1][index1], + encryptionTable[layer + 1][index2], mixnet[layer][switchIndex], r1,r2); switchIndex = (switchIndex + 1) % (n / 2); @@ -99,15 +94,13 @@ public class Mixer{ if (i == 1) { half = false; - i = 4; + i = 4; // avoid duplicate layer in the middle } } else - { - i <<= 1; - } + i <<= 1; } - return new Pair(proofsTable, encryptionsTable); + return new Pair(proofsTable, encryptionTable); } private int[] randomPermutation(int n){ @@ -130,23 +123,23 @@ public class Mixer{ private boolean[][] createMixNet(int n,int layers) { - int[] permutaion = randomPermutation(n); + int[] permutation = randomPermutation(n); int[] pi, piL, piR; - Queue permutaions = new ArrayBlockingQueue(n); + Queue permutationsQueue = new ArrayBlockingQueue(n); Graph graph; boolean[][] mixnet = new boolean[layers][n>>1]; - permutaions.add(permutaion); + permutationsQueue.add(permutation); for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size - { - for (int j = 0; j < n / 2; j += i / 2) // + { + for (int j = 0; j < n / 2; j += i / 2) // j == permutation index { - pi = permutaions.remove(); + pi = permutationsQueue.remove(); graph = new Graph(pi); piL = new int[i / 2]; piR = new int[i / 2]; - for (int k = 0; k < i / 2; k++) + for (int k = 0; k < i / 2; k++) // k == switch index in permutation j { mixnet[layers - layer - 1][k + j] = graph.getSwitchValue(k, true); mixnet[layer][k + j] = graph.getSwitchValue(k, false); @@ -162,10 +155,10 @@ public class Mixer{ piR[k] = pi[k] % (i / 2); } } - permutaions.add(piL); - permutaions.add(piR); + permutationsQueue.add(piL); + permutationsQueue.add(piR); } - } + } return mixnet; } From b502dc82d303673f0770dba2c214ef2bcd91f613 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 8 Dec 2015 00:15:16 +0200 Subject: [PATCH 03/66] updated mixer code --- mixer/src/main/java/mixer/Graph.java | 2 +- mixer/src/main/java/mixer/Mixer.java | 47 ++++++++++++++-------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/mixer/src/main/java/mixer/Graph.java b/mixer/src/main/java/mixer/Graph.java index d57a044..115d38d 100644 --- a/mixer/src/main/java/mixer/Graph.java +++ b/mixer/src/main/java/mixer/Graph.java @@ -10,7 +10,7 @@ class Graph private Node[] nodes; protected Graph(int[] permutation){ n = permutation.length; // n = 2^k - nDiv2 = n /2; + nDiv2 = n >> 1; createNodes(); createEdges(permutation); setSwitches(); diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index e8fee4b..4179e6a 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -6,6 +6,8 @@ import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import javafx.util.Pair; import java.util.Random; +import java.util.regex.Matcher; + import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto.*; @@ -30,41 +32,38 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer{ public Pair mix(List ciphertexts) throws InvalidProtocolBufferException{ int n = ciphertexts.size(); + int nDiv2 = n >> 1; // assert n = 2^k and n > 1 if( n <= 1 || ((n & (n-1)) != 0)) return null; //initialization - int layers = 0; - for (int i = n; i > 1; i>>=1) { - layers++; - } - layers<<=1; - layers--; + int layers = (int)(2 * Math.log(n)/Math.log(2)) - 1; // layers = 2logn -1 RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers][n]; - ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2]; + ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][nDiv2]; boolean[][] mixnet = createMixNet(n,layers); int index1, index2, switchIndex = 0; EncryptionRandomness r1 ,r2; RerandomizableEncryptedMessage e1, e2; boolean half = true; - //set first level of encryption + // set first level of encryption for (int j = 0; j < n; j++) { encryptionTable[0][j] = ciphertexts.get(j); } // main loop - int i = n; + int i = n,iDiv2; for (int layer = 0; layer < layers; layer++) // i == permutation size { + iDiv2 = i >> 1; for (int j = 0; j < n; j += i) // j == permutation index { - for (int k = 0; k < i / 2; k++) // k == elements index in permutation j + for (int k = 0; k < iDiv2; k++) // k == elements index in permutation j { index1 = k + j; - index2 = k + j + i / 2; + index2 = k + j + iDiv2; e1 = encryptionTable[layer][index1]; e2 = encryptionTable[layer][index2]; r1 = encryptor.generateRandomness(random); @@ -85,12 +84,12 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer{ encryptionTable[layer + 1][index2], mixnet[layer][switchIndex], r1,r2); - switchIndex = (switchIndex + 1) % (n / 2); + switchIndex = (switchIndex + 1) % nDiv2; } } if (half) { - i >>= 1; + i = iDiv2; if (i == 1) { half = false; @@ -127,32 +126,34 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer{ int[] pi, piL, piR; Queue permutationsQueue = new ArrayBlockingQueue(n); Graph graph; - boolean[][] mixnet = new boolean[layers][n>>1]; + int iDiv2; + int nDiv2 = n >> 1; + boolean[][] mixnet = new boolean[layers][nDiv2]; permutationsQueue.add(permutation); - for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size { - for (int j = 0; j < n / 2; j += i / 2) // j == permutation index + iDiv2 = i >> 1; + for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation index { pi = permutationsQueue.remove(); graph = new Graph(pi); - piL = new int[i / 2]; - piR = new int[i / 2]; - for (int k = 0; k < i / 2; k++) // k == switch index in permutation j + piL = new int[iDiv2]; + piR = new int[iDiv2]; + for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j { mixnet[layers - layer - 1][k + j] = graph.getSwitchValue(k, true); mixnet[layer][k + j] = graph.getSwitchValue(k, false); if (!mixnet[layers - layer - 1][k + j]) { - piL[k] = pi[k] % (i / 2); - piR[k] = pi[k + i / 2] % (i / 2); + piL[k] = pi[k] % iDiv2; + piR[k] = pi[k + iDiv2] % iDiv2; } else { - piL[k] = pi[k + i / 2] % (i / 2); - piR[k] = pi[k] % (i / 2); + piL[k] = pi[k + iDiv2] % iDiv2; + piR[k] = pi[k] % iDiv2; } } permutationsQueue.add(piL); From 23573666ec900f27bf0cf4d72d2bccbf2361e4f4 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 11 Dec 2015 14:41:26 +0200 Subject: [PATCH 04/66] mixer + prover + verifier --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../src/main/proto/meerkat/mixing.proto | 39 ++--- mixer/src/main/java/necessary/General.java | 41 +++++ mixer/src/main/java/necessary/Group.java | 14 ++ mixer/src/main/java/prover/Prover.java | 147 ++++++++++++++++++ mixer/src/main/java/verifier/Verifier.java | 80 ++++++++++ 6 files changed, 299 insertions(+), 24 deletions(-) create mode 100644 mixer/src/main/java/necessary/General.java create mode 100644 mixer/src/main/java/necessary/Group.java create mode 100644 mixer/src/main/java/prover/Prover.java create mode 100644 mixer/src/main/java/verifier/Verifier.java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3555c28..1ca625d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Tue Dec 01 01:04:39 IST 2015 +#Fri Dec 11 12:12:40 IST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 8e56e2e..882d882 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -8,34 +8,27 @@ import 'meerkat/crypto.proto'; message ZeroKnowledgeProof { message OrProof { - message GroupMember { - bytes data = 1; - } - message BigIntegerMsg { - bytes data = 1; - } - //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; - GroupMember g1 = 1; - GroupMember h1 = 2; - GroupMember g2 = 3; - GroupMember h2 = 4; - GroupMember g1Tag = 5; - GroupMember h1Tag = 6; - GroupMember g2Tag = 7; - GroupMember h2Tag = 8; + bytes g1 = 1; + bytes h1 = 2; + bytes g2 = 3; + bytes h2 = 4; + bytes g1Tag = 5; + bytes h1Tag = 6; + bytes g2Tag = 7; + bytes h2Tag = 8; //calc: u, v, uTag, vTag; - GroupMember u = 9; - GroupMember v = 10; - GroupMember uTag = 11; - GroupMember vTag = 12; + bytes u = 9; + bytes v = 10; + bytes uTag = 11; + bytes vTag = 12; //generated: c1,c2,z,zTag - BigIntegerMsg c1 = 13; - BigIntegerMsg c2 = 14; - BigIntegerMsg z = 15; - BigIntegerMsg zTag = 16; + bytes c1 = 13; + bytes c2 = 14; + bytes z = 15; + bytes zTag = 16; } OrProof first = 1; OrProof second = 2; diff --git a/mixer/src/main/java/necessary/General.java b/mixer/src/main/java/necessary/General.java new file mode 100644 index 0000000..b6a3707 --- /dev/null +++ b/mixer/src/main/java/necessary/General.java @@ -0,0 +1,41 @@ +package necessary; + +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; + +import com.google.protobuf.ByteString; + +public interface General { + + /* + given RerandomizableEncryptedMessage returns an equivalent ElGamalCiphertext + */ + ConcreteCrypto.ElGamalCiphertext calcRerandomizable2ElGamal(Crypto.RerandomizableEncryptedMessage enc); + + + /* + modulo operation over ByteString + */ + ByteString mod(ByteString dividend, ByteString divisor); + + /* + addition operation over ByteString + */ + ByteString add(ByteString a, ByteString b); + + /* + subtraction operation over ByteString + */ + ByteString sub(ByteString Subtraction, ByteString subtrahend); + + + /* + multiplication operation over ByteString + */ + ByteString mul(ByteString a, ByteString b); + + /* + hash operation over ByteString + */ + ByteString hash(ByteString... arr); +} diff --git a/mixer/src/main/java/necessary/Group.java b/mixer/src/main/java/necessary/Group.java new file mode 100644 index 0000000..544b1d7 --- /dev/null +++ b/mixer/src/main/java/necessary/Group.java @@ -0,0 +1,14 @@ +package necessary; + + +import com.google.protobuf.ByteString; + +public interface Group { + + ByteString getG(); + ByteString getH(); + ByteString div(ByteString dividend, ByteString divisor); + ByteString mul(ByteString a, ByteString b); + ByteString pow(ByteString bas, ByteString exp); + ByteString groupSize(); +} diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java new file mode 100644 index 0000000..8d0f3c6 --- /dev/null +++ b/mixer/src/main/java/prover/Prover.java @@ -0,0 +1,147 @@ +package prover; + +import com.google.protobuf.ByteString; +import meerkat.crypto.Encryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import necessary.General; +import necessary.Group; + +import java.util.Random; + +public class Prover implements Mix2ZeroKnowledgeProver { + + Group group; + General general; + Random rand; + Encryption encryptor; + + public Prover(Group group,Random rand,Encryption encryptor,General general) { + this.group = group; + this.rand = rand; + this.encryptor = encryptor; + this.general = general; + } + + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean switched, + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2) { + + Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; + if (!switched) + { + first = createOrProof(in1, out1, in2, out1, r1, true); + second = createOrProof(in1, out1, in1, out2, r1, true); + third = createOrProof(in2, out1, in2, out2, r2, false); + fourth = createOrProof(in1, out2, in2, out2, r2, false); + } + else + { + first = createOrProof(in1, out1, in2, out1, r2, false); + second = createOrProof(in1, out1, in1, out2, r1, false); + third = createOrProof(in2, out1, in2, out2, r2, true); + fourth = createOrProof(in1, out2, in2, out2, r1, true); + } + return Mixing.ZeroKnowledgeProof.newBuilder() + .setFirst(first) + .setSecond(second) + .setThird(third) + .setFourth(fourth) + .build(); + } + + private Mixing.ZeroKnowledgeProof.OrProof createOrProof(Crypto.RerandomizableEncryptedMessage e1, + Crypto.RerandomizableEncryptedMessage e2, + Crypto.RerandomizableEncryptedMessage e1New, + Crypto.RerandomizableEncryptedMessage e2New, + Crypto.EncryptionRandomness x, + boolean flag){ + + ElGamalCiphertext e1ElGamal = general.calcRerandomizable2ElGamal(e1); + ElGamalCiphertext e2ElGamal = general.calcRerandomizable2ElGamal(e2); + ElGamalCiphertext e1TagElGamal = general.calcRerandomizable2ElGamal(e1New); + ElGamalCiphertext e2TagElGamal = general.calcRerandomizable2ElGamal(e2New); + + + return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,x,flag); + } + + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalCiphertext e1, + ElGamalCiphertext e2, + ElGamalCiphertext e1New, + ElGamalCiphertext e2New, + Crypto.EncryptionRandomness x, + boolean flag) { + ByteString g1 = group.getG(); + ByteString h1 = group.div(e1New.getC1(),e1.getC1()); + ByteString g2 = group.getH(); + ByteString h2 = group.div(e1New.getC2(),e1.getC2()); + + ByteString g1Tag = group.getG(); + ByteString h1Tag = group.div(e2New.getC1(),e2.getC1()); + ByteString g2Tag = group.getH(); + ByteString h2Tag = group.div(e2New.getC2(),e2.getC2()); + + ByteString r = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + ByteString u,v,uTag,vTag,c1,c2,z,zTag; + if (flag) + { + c2 = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + zTag = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + //step 1 + u = group.pow(g1, r); + v = group.pow(g2, r); + uTag = group.div(group.pow(g1Tag, zTag), group.pow(h1Tag, c2)); + vTag = group.div(group.pow(g2Tag, zTag), group.pow(h2Tag, c2)); + //step 2 + // c1 = (hash(input + step1) + group size - c2)% group size + c1 = general.mod(general.add(general.hash(g1, h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag, u, v, uTag, vTag), general.sub(group.groupSize(), c2)),group.groupSize()); + //step 3 + //z = (r + c1 * x) % group size; + z = general.mod(general.add(r,general.mul(c1,x.getData())),group.groupSize()); + } + else + { + c1 = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + z = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + //step 1 + uTag = group.pow(g1Tag, r); + vTag = group.pow(g2Tag, r); + u = group.div(group.pow(g1, z), group.pow(h1, c1)); + v = group.div(group.pow(g2, z), group.pow(h2, c1)); + //step 2 + // c1 = (hash(input + step1) + group size - c1)% group size + c2 = general.mod(general.add(general.hash(g1, h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag, u, v, uTag, vTag), general.sub(group.groupSize(), c1)),group.groupSize()); + //step 3 + //zTag = (r + c2 * x) % group size; + zTag = general.mod(general.add(r,general.mul(c2,x.getData())),group.groupSize()); + } + return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() + .setG1(g1) + .setH1(h1) + .setG2(g2) + .setH2(h2) + .setG1Tag(g1Tag) + .setH1Tag(h1Tag) + .setG2Tag(g2Tag) + .setH2Tag(h2Tag) + .setU(u) + .setV(v) + .setUTag(uTag) + .setVTag(vTag) + .setC1(c1) + .setC2(c2) + .setZ(z) + .setZTag(zTag) + .build(); + } + + +} + diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java new file mode 100644 index 0000000..b7894df --- /dev/null +++ b/mixer/src/main/java/verifier/Verifier.java @@ -0,0 +1,80 @@ +package verifier; + +import meerkat.crypto.Encryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import necessary.General; +import necessary.Group; + + +public class Verifier implements Mix2ZeroKnowledgeVerifier { + + /** + * Return true iff the proof is valid. + * @param in1 + * @param in2 + * @param out1 + * @param out2 + * @return + */ + + Group group; + General general; + + public Verifier(Group group,General general) { + this.group = group; + this.general = general; + } + + public boolean verify(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + Mixing.ZeroKnowledgeProof proof) + { + + ElGamalCiphertext e1ElGamal = general.calcRerandomizable2ElGamal(in1); + ElGamalCiphertext e2ElGamal = general.calcRerandomizable2ElGamal(in2); + ElGamalCiphertext e1TagElGamal = general.calcRerandomizable2ElGamal(out1); + ElGamalCiphertext e2TagElGamal = general.calcRerandomizable2ElGamal(out2); + + return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getFirst()) && + verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getSecond()) && + verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getThird()) && + verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getFourth()); + } + + public boolean verifyElGamaOrProof(ElGamalCiphertext e1, + ElGamalCiphertext e2, + ElGamalCiphertext e1New, + ElGamalCiphertext e2New, + Mixing.ZeroKnowledgeProof.OrProof orProof) + { + + return //input + orProof.getG1().equals(group.getG())&& + orProof.getH1().equals(group.div(e1New.getC1(), e1.getC1()))&& + orProof.getG2().equals(group.getH())&& + orProof.getH2().equals(group.div(e1New.getC2(), e1.getC2()))&& + // input' + orProof.getG1Tag().equals(group.getG())&& + orProof.getH1Tag().equals(group.div(e2New.getC1(), e2.getC1()))&& + orProof.getG2Tag().equals(group.getH())&& + orProof.getH2Tag().equals(group.div(e2New.getC2(), e2.getC2())) && + // hash + // assert (c1 + c2 ) % group size == hash (imput + step1) % group size + general.mod((general.add(orProof.getC1(),orProof.getC2())),group.groupSize()) + .equals(general.mod(general.hash(orProof.getG1(), orProof.getH1(), orProof.getG2(), orProof.getH2(), + orProof.getG1Tag(), orProof.getH1Tag(), orProof.getG2Tag(), orProof.getH2Tag(), + orProof.getV(),orProof.getU(),orProof.getVTag(),orProof.getUTag()) , group.groupSize()))&& + // proof + // g1 ^ z == u * ( h1 ^ c1 ) && g2 ^ z == v * ( h2 ^ c1 ) && the same for tag case + group.pow(orProof.getG1(), orProof.getZ()).equals(group.mul(orProof.getU(), group.pow(orProof.getH1(),orProof.getC1()))) && + group.pow(orProof.getG2(), orProof.getZ()).equals(group.mul(orProof.getV(), group.pow(orProof.getH2(),orProof.getC1()))) && + group.pow(orProof.getG1Tag(), orProof.getZTag()).equals(group.mul(orProof.getUTag(), group.pow(orProof.getH1Tag(),orProof.getC2()))) && + group.pow(orProof.getG2Tag(), orProof.getZTag()).equals(group.mul(orProof.getVTag(), group.pow(orProof.getH2Tag(),orProof.getC2()))); + + } +} From c37d30baf6de5919ee58c8542e1e9a14f5c12bc6 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Mon, 14 Dec 2015 17:54:44 +0200 Subject: [PATCH 05/66] work with qilin --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../crypto/concrete/ECElGamalEncryption.java | 2 +- .../java/meerkat/crypto/mixnet/Mixer.java | 6 +- .../src/main/proto/meerkat/mixing.proto | 14 ++++ mixer/src/main/java/mixer/Mixer.java | 3 +- mixer/src/main/java/necessary/General.java | 30 ++------ .../src/main/java/necessary/GeneralImpl.java | 46 +++++++++++++ mixer/src/main/java/necessary/Group.java | 8 +-- mixer/src/main/java/necessary/GroupImpl.java | 39 +++++++++++ mixer/src/main/java/prover/Prover.java | 69 ++++++++++++++----- mixer/src/main/java/verifier/Verifier.java | 44 ++++++++---- 11 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 mixer/src/main/java/necessary/GeneralImpl.java create mode 100644 mixer/src/main/java/necessary/GroupImpl.java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1ca625d..1e04d9c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Fri Dec 11 12:12:40 IST 2015 +#Mon Dec 14 14:35:37 IST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 8718dd7..c281dd7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -115,7 +115,7 @@ public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); - Pair originalCipher = new Pair<>( + Pair originalCipher = new Pair( curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); Pair newCipher = elGamalPK.add(originalCipher, randomizer); diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index bbd999e..dc2f819 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -1,16 +1,16 @@ package meerkat.crypto.mixnet; import com.google.protobuf.InvalidProtocolBufferException; -import javafx.util.Pair; +import qilin.util.Pair; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import java.util.List; -import static meerkat.protobuf.Voting.*; /** * Created by talm on 25/10/15. */ public interface Mixer { - public Pair mix(List ciphertexts) throws InvalidProtocolBufferException; + public Pair + mix(List ciphertexts) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 882d882..763f46b 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -8,6 +8,20 @@ import 'meerkat/crypto.proto'; message ZeroKnowledgeProof { message OrProof { + message ForRandomOracle{ + bytes g1 = 1; + bytes h1 = 2; + bytes g2 = 3; + bytes h2 = 4; + bytes g1Tag = 5; + bytes h1Tag = 6; + bytes g2Tag = 7; + bytes h2Tag = 8; + bytes u = 9; + bytes v = 10; + bytes uTag = 11; + bytes vTag = 12; + } //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; bytes g1 = 1; bytes h1 = 2; diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 4179e6a..7e7c0b9 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -4,9 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; -import javafx.util.Pair; +import qilin.util.Pair; import java.util.Random; -import java.util.regex.Matcher; import com.google.protobuf.InvalidProtocolBufferException; diff --git a/mixer/src/main/java/necessary/General.java b/mixer/src/main/java/necessary/General.java index b6a3707..92df602 100644 --- a/mixer/src/main/java/necessary/General.java +++ b/mixer/src/main/java/necessary/General.java @@ -4,6 +4,9 @@ import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import com.google.protobuf.ByteString; +import meerkat.protobuf.Mixing; + +import java.math.BigInteger; public interface General { @@ -12,30 +15,11 @@ public interface General { */ ConcreteCrypto.ElGamalCiphertext calcRerandomizable2ElGamal(Crypto.RerandomizableEncryptedMessage enc); + ByteString getG(); + ByteString getH(); /* - modulo operation over ByteString + fiat shamir assumption */ - ByteString mod(ByteString dividend, ByteString divisor); - - /* - addition operation over ByteString - */ - ByteString add(ByteString a, ByteString b); - - /* - subtraction operation over ByteString - */ - ByteString sub(ByteString Subtraction, ByteString subtrahend); - - - /* - multiplication operation over ByteString - */ - ByteString mul(ByteString a, ByteString b); - - /* - hash operation over ByteString - */ - ByteString hash(ByteString... arr); + BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input); } diff --git a/mixer/src/main/java/necessary/GeneralImpl.java b/mixer/src/main/java/necessary/GeneralImpl.java new file mode 100644 index 0000000..9a4fda6 --- /dev/null +++ b/mixer/src/main/java/necessary/GeneralImpl.java @@ -0,0 +1,46 @@ +package necessary; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import qilin.primitives.RandomOracle; +import java.math.BigInteger; + +/** + * Created by Tzlil on 12/14/2015. + */ +public class GeneralImpl implements General { + + + private final RandomOracle rndomOracle; + private final ByteString h; + private final ByteString g; + + public GeneralImpl(RandomOracle randomOracle,ByteString g,ByteString h) { + this.rndomOracle = randomOracle; + this.h = h; + this.g = g; + } + + @Override + public ConcreteCrypto.ElGamalCiphertext calcRerandomizable2ElGamal(Crypto.RerandomizableEncryptedMessage enc) { + return null; + } + + @Override + public ByteString getG() { + return g; + } + + @Override + public ByteString getH() { + return h; + } + + @Override + public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { + byte[] arr = input.toByteArray(); + return new BigInteger(this.rndomOracle.hash(arr,arr.length)); + } +} diff --git a/mixer/src/main/java/necessary/Group.java b/mixer/src/main/java/necessary/Group.java index 544b1d7..27c57d8 100644 --- a/mixer/src/main/java/necessary/Group.java +++ b/mixer/src/main/java/necessary/Group.java @@ -3,12 +3,12 @@ package necessary; import com.google.protobuf.ByteString; +import java.math.BigInteger; + public interface Group { - ByteString getG(); - ByteString getH(); ByteString div(ByteString dividend, ByteString divisor); ByteString mul(ByteString a, ByteString b); - ByteString pow(ByteString bas, ByteString exp); - ByteString groupSize(); + ByteString pow(ByteString bas, BigInteger exp); + BigInteger groupSize(); } diff --git a/mixer/src/main/java/necessary/GroupImpl.java b/mixer/src/main/java/necessary/GroupImpl.java new file mode 100644 index 0000000..5e98248 --- /dev/null +++ b/mixer/src/main/java/necessary/GroupImpl.java @@ -0,0 +1,39 @@ +package necessary; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 12/14/2015. + */ +public class GroupImpl implements Group { + + qilin.primitives.Group qilinInstance; + public GroupImpl(qilin.primitives.Group qilinInstance) { + this.qilinInstance = qilinInstance; + } + + + @Override + public ByteString div(ByteString dividend, ByteString divisor) { + return mul(dividend,qilinInstance.negate(divisor)); + } + + @Override + public ByteString mul(ByteString a, ByteString b) { + return qilinInstance.add(a,b); + } + + @Override + public ByteString pow(ByteString bas, BigInteger exp) { + return qilinInstance.multiply(bas,exp); + } + + @Override + public BigInteger groupSize() { + return qilinInstance.orderUpperBound(); + } +} + diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 8d0f3c6..789f323 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -9,6 +9,8 @@ import meerkat.protobuf.Mixing; import necessary.General; import necessary.Group; + +import java.math.BigInteger; import java.util.Random; public class Prover implements Mix2ZeroKnowledgeProver { @@ -78,22 +80,23 @@ public class Prover implements Mix2ZeroKnowledgeProver { ElGamalCiphertext e2New, Crypto.EncryptionRandomness x, boolean flag) { - ByteString g1 = group.getG(); + ByteString g1 = general.getG(); ByteString h1 = group.div(e1New.getC1(),e1.getC1()); - ByteString g2 = group.getH(); + ByteString g2 = general.getH(); ByteString h2 = group.div(e1New.getC2(),e1.getC2()); - ByteString g1Tag = group.getG(); + ByteString g1Tag = general.getG(); ByteString h1Tag = group.div(e2New.getC1(),e2.getC1()); - ByteString g2Tag = group.getH(); + ByteString g2Tag = general.getH(); ByteString h2Tag = group.div(e2New.getC2(),e2.getC2()); - ByteString r = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); - ByteString u,v,uTag,vTag,c1,c2,z,zTag; + BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + BigInteger c1,c2,z,zTag; + ByteString u,v,uTag,vTag; if (flag) { - c2 = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); - zTag = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); //step 1 u = group.pow(g1, r); v = group.pow(g2, r); @@ -101,15 +104,30 @@ public class Prover implements Mix2ZeroKnowledgeProver { vTag = group.div(group.pow(g2Tag, zTag), group.pow(h2Tag, c2)); //step 2 // c1 = (hash(input + step1) + group size - c2)% group size - c1 = general.mod(general.add(general.hash(g1, h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag, u, v, uTag, vTag), general.sub(group.groupSize(), c2)),group.groupSize()); + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(g1) + .setH1(h1) + .setG2(g2) + .setH2(h2) + .setG1Tag(g1Tag) + .setH1Tag(h1Tag) + .setG2Tag(g2Tag) + .setH2Tag(h2Tag) + .setU(u) + .setV(v) + .setUTag(uTag) + .setVTag(vTag) + .build(); + c1 = general.hash(forRandomOracle).add(group.groupSize().subtract(c2)).mod(group.groupSize()); //step 3 //z = (r + c1 * x) % group size; - z = general.mod(general.add(r,general.mul(c1,x.getData())),group.groupSize()); + z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.groupSize()); } else { - c1 = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); - z = general.mod(encryptor.generateRandomness(rand).getData(),group.groupSize()); + c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); //step 1 uTag = group.pow(g1Tag, r); vTag = group.pow(g2Tag, r); @@ -117,10 +135,25 @@ public class Prover implements Mix2ZeroKnowledgeProver { v = group.div(group.pow(g2, z), group.pow(h2, c1)); //step 2 // c1 = (hash(input + step1) + group size - c1)% group size - c2 = general.mod(general.add(general.hash(g1, h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag, u, v, uTag, vTag), general.sub(group.groupSize(), c1)),group.groupSize()); + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(g1) + .setH1(h1) + .setG2(g2) + .setH2(h2) + .setG1Tag(g1Tag) + .setH1Tag(h1Tag) + .setG2Tag(g2Tag) + .setH2Tag(h2Tag) + .setU(u) + .setV(v) + .setUTag(uTag) + .setVTag(vTag) + .build(); + c2 = general.hash(forRandomOracle).add(group.groupSize().subtract(c1)).mod(group.groupSize()); //step 3 //zTag = (r + c2 * x) % group size; - zTag = general.mod(general.add(r,general.mul(c2,x.getData())),group.groupSize()); + zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.groupSize()); } return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() .setG1(g1) @@ -135,10 +168,10 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setV(v) .setUTag(uTag) .setVTag(vTag) - .setC1(c1) - .setC2(c2) - .setZ(z) - .setZTag(zTag) + .setC1(ByteString.copyFrom(c1.toByteArray())) + .setC2(ByteString.copyFrom(c2.toByteArray())) + .setZ(ByteString.copyFrom(z.toByteArray())) + .setZTag(ByteString.copyFrom(zTag.toByteArray())) .build(); } diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index b7894df..197e012 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -8,6 +8,8 @@ import meerkat.protobuf.Mixing; import necessary.General; import necessary.Group; +import java.math.BigInteger; + public class Verifier implements Mix2ZeroKnowledgeVerifier { @@ -53,28 +55,46 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { Mixing.ZeroKnowledgeProof.OrProof orProof) { + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(orProof.getG1()) + .setH1(orProof.getH1()) + .setG2(orProof.getG2()) + .setH2(orProof.getH2()) + .setG1Tag(orProof.getG1Tag()) + .setH1Tag(orProof.getH1Tag()) + .setG2Tag(orProof.getG2Tag()) + .setH2Tag(orProof.getH2Tag()) + .setU(orProof.getU()) + .setV(orProof.getV()) + .setUTag(orProof.getUTag()) + .setVTag(orProof.getVTag()) + .build(); + return //input - orProof.getG1().equals(group.getG())&& + orProof.getG1().equals(general.getG())&& orProof.getH1().equals(group.div(e1New.getC1(), e1.getC1()))&& - orProof.getG2().equals(group.getH())&& + orProof.getG2().equals(general.getH())&& orProof.getH2().equals(group.div(e1New.getC2(), e1.getC2()))&& // input' - orProof.getG1Tag().equals(group.getG())&& + orProof.getG1Tag().equals(general.getG())&& orProof.getH1Tag().equals(group.div(e2New.getC1(), e2.getC1()))&& - orProof.getG2Tag().equals(group.getH())&& + orProof.getG2Tag().equals(general.getH())&& orProof.getH2Tag().equals(group.div(e2New.getC2(), e2.getC2())) && // hash // assert (c1 + c2 ) % group size == hash (imput + step1) % group size - general.mod((general.add(orProof.getC1(),orProof.getC2())),group.groupSize()) - .equals(general.mod(general.hash(orProof.getG1(), orProof.getH1(), orProof.getG2(), orProof.getH2(), - orProof.getG1Tag(), orProof.getH1Tag(), orProof.getG2Tag(), orProof.getH2Tag(), - orProof.getV(),orProof.getU(),orProof.getVTag(),orProof.getUTag()) , group.groupSize()))&& + new BigInteger(orProof.getC1().toByteArray()).add(new BigInteger(orProof.getC2().toByteArray())).mod(group.groupSize()) + .equals(general.hash(forRandomOracle).mod(group.groupSize()).mod(group.groupSize()))&& // proof // g1 ^ z == u * ( h1 ^ c1 ) && g2 ^ z == v * ( h2 ^ c1 ) && the same for tag case - group.pow(orProof.getG1(), orProof.getZ()).equals(group.mul(orProof.getU(), group.pow(orProof.getH1(),orProof.getC1()))) && - group.pow(orProof.getG2(), orProof.getZ()).equals(group.mul(orProof.getV(), group.pow(orProof.getH2(),orProof.getC1()))) && - group.pow(orProof.getG1Tag(), orProof.getZTag()).equals(group.mul(orProof.getUTag(), group.pow(orProof.getH1Tag(),orProof.getC2()))) && - group.pow(orProof.getG2Tag(), orProof.getZTag()).equals(group.mul(orProof.getVTag(), group.pow(orProof.getH2Tag(),orProof.getC2()))); + group.pow(orProof.getG1(), new BigInteger(orProof.getZ().toByteArray())) + .equals(group.mul(orProof.getU(), group.pow(orProof.getH1(),new BigInteger(orProof.getC1().toByteArray())))) && + group.pow(orProof.getG2(), new BigInteger(orProof.getZ().toByteArray())) + .equals(group.mul(orProof.getV(), group.pow(orProof.getH2(),new BigInteger(orProof.getC1().toByteArray())))) && + group.pow(orProof.getG1Tag(), new BigInteger(orProof.getZTag().toByteArray())) + .equals(group.mul(orProof.getUTag(), group.pow(orProof.getH1Tag(),new BigInteger(orProof.getC2().toByteArray())))) && + group.pow(orProof.getG2Tag(), new BigInteger(orProof.getZTag().toByteArray())) + .equals(group.mul(orProof.getVTag(), group.pow(orProof.getH2Tag(),new BigInteger(orProof.getC2().toByteArray())))); } } From 767d73c14371e1ae6c046605bc217204274b610e Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 15 Dec 2015 16:44:50 +0200 Subject: [PATCH 06/66] smal changes after code review --- .../mixnet/Mix2ZeroKnowledgeProver.java | 1 + mixer/src/main/java/mixer/Graph.java | 118 ----------- mixer/src/main/java/mixer/MixNetwork.java | 195 ++++++++++++++++++ mixer/src/main/java/mixer/Mixer.java | 170 ++++----------- mixer/src/main/java/mixer/Switch.java | 17 ++ mixer/src/main/java/prover/Prover.java | 4 +- 6 files changed, 258 insertions(+), 247 deletions(-) delete mode 100644 mixer/src/main/java/mixer/Graph.java create mode 100644 mixer/src/main/java/mixer/MixNetwork.java create mode 100644 mixer/src/main/java/mixer/Switch.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index 1113bfd..a76b5fd 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -15,4 +15,5 @@ public interface Mix2ZeroKnowledgeProver { Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2); + } diff --git a/mixer/src/main/java/mixer/Graph.java b/mixer/src/main/java/mixer/Graph.java deleted file mode 100644 index 115d38d..0000000 --- a/mixer/src/main/java/mixer/Graph.java +++ /dev/null @@ -1,118 +0,0 @@ -package mixer; - -import java.util.ArrayList; -import java.util.List; - -class Graph -{ - private int n; - private int nDiv2; - private Node[] nodes; - protected Graph(int[] permutation){ - n = permutation.length; // n = 2^k - nDiv2 = n >> 1; - createNodes(); - createEdges(permutation); - setSwitches(); - } - - // provide an access to graph to algorithm result - // index must be less then n/2 - protected boolean getSwitchValue(int index,boolean up) - { - return up ? nodes[index].on : nodes[index + n / 2].on; - } - - // create two lines of nodes size n/2 each - // the value of the i th node is (i,i+n/2) if i < n /2 (first line) - // otherwise its value is (i - n/2 , i) (second line) - private void createNodes() - { - nodes = new Node[n]; - for (int i = 0; i < n / 2; i++) - { - nodes[i] = new Node(true); - nodes[i + nDiv2] = new Node(false); - } - } - - // create an edge between each pair of nodes i,j from different lines (i index of the first line) - // if exists k in i th node's value and t in j th node's value - // s.t permutation[k] == t - // the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) - // Note: in purpose to avoid edge cases, each node has exactly two edges - private void createEdges(int[] permutation) - { - int j; - for (int i = 0; i < nDiv2; i++) - { - j = (permutation[i] % nDiv2) + nDiv2; - nodes[i].edges.add(new Edge(nodes[j], (permutation[i] >= nDiv2))); - nodes[j].edges.add(new Edge(nodes[i], (permutation[i] >= nDiv2))); - - j = (permutation[i + nDiv2] % nDiv2) + nDiv2; - nodes[i].edges.add(new Edge(nodes[j], (permutation[i + nDiv2] < nDiv2))); - nodes[j].edges.add(new Edge(nodes[i], (permutation[i + nDiv2] < nDiv2))); - } - } - - // set switch's value (on/off) for each switch (node) - // s.t if nodes i,j connected by edge e, i th switch's value - // must be equal to j's if e is broken or not equal if e is not broken - private void setSwitches() - { - Node node; - boolean v; - Edge e0,e1; - // iterate over first line of nodes - for (int i = 0; i < nDiv2; i++) - { - node = nodes[i]; - if (node.set) - continue; - //select default value for first node in connected component - v = false; - // set value to all reachable nodes from node - while (true) - { - node.set = true; - node.on = v; - e0 = node.edges.get(0); e1 = node.edges.get(1); - if (e0.neighbor.set && e1.neighbor.set) - break; - v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; - node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; - } - } - } - - //inner classes - - private class Node - { - public boolean up; - public List edges; - public boolean on; - public boolean set; - public Node(boolean up) - { - this.up = up; - edges = new ArrayList(); - set = false; - } - } - - private class Edge - { - public Node neighbor; - public boolean broken; - public Edge(Node neighbor, boolean broken) - { - this.neighbor = neighbor; - this.broken = broken; - } - } - - -} - diff --git a/mixer/src/main/java/mixer/MixNetwork.java b/mixer/src/main/java/mixer/MixNetwork.java new file mode 100644 index 0000000..219886f --- /dev/null +++ b/mixer/src/main/java/mixer/MixNetwork.java @@ -0,0 +1,195 @@ +package mixer; + +import com.google.protobuf.Enum; + +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.Random; + +/** + * Created by Tzlil on 12/15/2015. + */ +public class MixNetwork { + + private final Switch[][] switches; + private final Random random; + + public MixNetwork(int n,int layers,Random random) + { + this.random = random; + int[] permutation = randomPermutation(n); + int[] pi, piL, piR; + Queue permutationsQueue = new ArrayBlockingQueue(n); + Graph graph; + int iDiv2; + int nDiv2 = n >> 1; + switches = new Switch[layers][nDiv2]; + int index1,index2; + + permutationsQueue.add(permutation); + for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size + { + iDiv2 = i >> 1; + for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation start index + { + pi = permutationsQueue.remove(); + graph = new Graph(pi); + piL = new int[iDiv2]; + piR = new int[iDiv2]; + for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j + { + index1 = k + j; + index2 = k + j + iDiv2; + switches[layers - layer - 1][k + j] = new Switch(index1,index2,layers - layer - 1,graph.getSwitchValue(k, true)); + switches[layer][k + j] = new Switch(index1,index2,layer,graph.getSwitchValue(k, false)); + + if (!switches[layers - layer - 1][k + j].value) { + piL[k] = pi[k] % iDiv2; + piR[k] = pi[k + iDiv2] % iDiv2; + } else { + piL[k] = pi[k + iDiv2] % iDiv2; + piR[k] = pi[k] % iDiv2; + } + } + permutationsQueue.add(piL); + permutationsQueue.add(piR); + } + } + } + + public Switch[] getSwitchesByLayer(int layer) + { + return switches[layer]; + } + + + + private int[] randomPermutation(int n){ + List numbers= new ArrayList(n); + for (int i = 0; i < n; i++) + { + numbers.add(i); + } + + int[] result = new int[n]; + int index; + for (int i = 0; i < n; i++) + { + index = random.nextInt(n - i); + result[i] = numbers.get(index); + numbers.remove(index); + } + return result; + } + + private class Graph { + private int n; + private int nDiv2; + private Node[][] nodes; + protected Graph(int[] permutation){ + n = permutation.length; // n = 2^k + nDiv2 = n >> 1; + createNodes(); + createEdges(permutation); + setSwitches(); + } + + // provide an access to algorithm result + // index must be less then n/2 + protected boolean getSwitchValue(int index,boolean up) + { + return up ? nodes[0][index].value : nodes[1][index].value; + } + + // create two lines of nodes size n/2 each + // the value of the i th node is (i,i+n/2) if i < n /2 (first line) + // otherwise its value is (i - n/2 , i) (second line) + private void createNodes() + { + nodes = new Node[2][nDiv2]; + for (int i = 0; i < nDiv2; i++) + { + nodes[0][i] = new Node(); + nodes[1][i] = new Node(); + } + } + + // create an edge between each pair of nodes i,j from different lines (i index of the first line) + // if exists k in i th node's value and t in j th node's value + // s.t permutation[k] == t + // the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) + // Note: in purpose to avoid edge cases, each node has exactly two edges + private void createEdges(int[] permutation) + { + int j; + for (int i = 0; i < nDiv2; i++) + { + j = permutation[i] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i] >= nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i] >= nDiv2))); + + j = permutation[i + nDiv2] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i + nDiv2] < nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i + nDiv2] < nDiv2))); + } + } + + // set switch's value (on/off) for each switch (node) + // s.t if nodes i,j connected by edge e, i th switch's value + // must be equal to j's if e is broken or not equal if e is not broken + private void setSwitches() + { + Node node; + boolean v; + Edge e0,e1; + // iterate over first line of nodes + for (int i = 0; i < nDiv2; i++) + { + node = nodes[0][i]; + if (node.set) + continue; + //select default value for first node in connected component + v = false; + // set value to all reachable nodes from node + while (true) + { + node.set = true; + node.value = v; + e0 = node.edges.get(0); e1 = node.edges.get(1); + if (e0.neighbor.set && e1.neighbor.set) + break; + v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; + node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; + } + } + } + + //inner classes + private class Node + { + public List edges; + private boolean value; + private boolean set; + public Node() + { + edges = new ArrayList(2); + set = false; + } + } + + private class Edge + { + public Node neighbor; + public boolean broken; + public Edge(Node neighbor, boolean broken) + { + this.neighbor = neighbor; + this.broken = broken; + } + } + } + + +} diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 7e7c0b9..97981b7 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -2,8 +2,6 @@ package mixer; import java.util.ArrayList; import java.util.List; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; import qilin.util.Pair; import java.util.Random; @@ -15,151 +13,69 @@ import meerkat.protobuf.Mixing.*; import meerkat.crypto.Encryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -public class Mixer implements meerkat.crypto.mixnet.Mixer{ - +public class Mixer implements meerkat.crypto.mixnet.Mixer { + private Random random; - private Mix2ZeroKnowledgeProver prover; + private Mix2ZeroKnowledgeProver prover; private Encryption encryptor; - - public Mixer(Random rand,Mix2ZeroKnowledgeProver prov,Encryption enc) { + + public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc) { this.random = rand; this.prover = prov; this.encryptor = enc; - + } - - public Pair mix(List ciphertexts) throws InvalidProtocolBufferException{ + + public Pair mix(List ciphertexts) throws InvalidProtocolBufferException { int n = ciphertexts.size(); int nDiv2 = n >> 1; // assert n = 2^k and n > 1 - if( n <= 1 || ((n & (n-1)) != 0)) + if (n <= 1 || ((n & (n - 1)) != 0)) return null; //initialization - int layers = (int)(2 * Math.log(n)/Math.log(2)) - 1; // layers = 2logn -1 - RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers][n]; - ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][nDiv2]; - boolean[][] mixnet = createMixNet(n,layers); - int index1, index2, switchIndex = 0; - EncryptionRandomness r1 ,r2; - RerandomizableEncryptedMessage e1, e2; - boolean half = true; - - // set first level of encryption - for (int j = 0; j < n; j++) - { - encryptionTable[0][j] = ciphertexts.get(j); - } + int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 + RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + int index1, index2, switchIndex = 0; + EncryptionRandomness r1, r2; + RerandomizableEncryptedMessage e1, e2; + boolean half = true; + MixNetwork mixNetwork = new MixNetwork(n,layers,random); + Switch[] switchesLayer; - // main loop - int i = n,iDiv2; - for (int layer = 0; layer < layers; layer++) // i == permutation size - { - iDiv2 = i >> 1; - for (int j = 0; j < n; j += i) // j == permutation index - { - for (int k = 0; k < iDiv2; k++) // k == elements index in permutation j - { - index1 = k + j; - index2 = k + j + iDiv2; - e1 = encryptionTable[layer][index1]; - e2 = encryptionTable[layer][index2]; - r1 = encryptor.generateRandomness(random); - r2 = encryptor.generateRandomness(random); - if (!mixnet[layer][switchIndex]) - { - encryptionTable[layer+1][index1] = encryptor.rerandomize(e1, r1); - encryptionTable[layer+1][index2] = encryptor.rerandomize(e2,r2); - - } - else - { - encryptionTable[layer+1][index1] = encryptor.rerandomize(e2,r2); - encryptionTable[layer+1][index2] = encryptor.rerandomize(e1,r1); - } - proofsTable[layer][switchIndex] = - prover.prove(e1, e2, encryptionTable[layer + 1][index1], - encryptionTable[layer + 1][index2], - mixnet[layer][switchIndex], r1,r2); - - switchIndex = (switchIndex + 1) % nDiv2; - } - } - if (half) - { - i = iDiv2; - if (i == 1) - { - half = false; - i = 4; // avoid duplicate layer in the middle - } - } - else - i <<= 1; - } - return new Pair(proofsTable, encryptionTable); - } - - private int[] randomPermutation(int n){ - List numbers= new ArrayList(n); - for (int i = 0; i < n; i++) - { - numbers.add(i); + // set first level of encryption + for (int j = 0; j < n; j++) { + encryptionTable[0][j] = ciphertexts.get(j); } - int[] result = new int[n]; - int index; - for (int i = 0; i < n; i++) + // main loop + for (int layer = 0; layer < layers; layer++) { - index = random.nextInt(n - i); - result[i] = numbers.get(index); - numbers.remove(index); - } - return result; - } - - private boolean[][] createMixNet(int n,int layers) - { - int[] permutation = randomPermutation(n); - int[] pi, piL, piR; - Queue permutationsQueue = new ArrayBlockingQueue(n); - Graph graph; - int iDiv2; - int nDiv2 = n >> 1; - boolean[][] mixnet = new boolean[layers][nDiv2]; + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + r1 = encryptor.generateRandomness(random); + r2 = encryptor.generateRandomness(random); + if (!sw.value) { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); - permutationsQueue.add(permutation); - for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size - { - iDiv2 = i >> 1; - for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation index - { - pi = permutationsQueue.remove(); - graph = new Graph(pi); - piL = new int[iDiv2]; - piR = new int[iDiv2]; - for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j - { - mixnet[layers - layer - 1][k + j] = graph.getSwitchValue(k, true); - mixnet[layer][k + j] = graph.getSwitchValue(k, false); - - if (!mixnet[layers - layer - 1][k + j]) - { - piL[k] = pi[k] % iDiv2; - piR[k] = pi[k + iDiv2] % iDiv2; - } - else - { - piL[k] = pi[k + iDiv2] % iDiv2; - piR[k] = pi[k] % iDiv2; - } + } else { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); } - permutationsQueue.add(piL); - permutationsQueue.add(piR); + proofsTable[layer][switchIndex] = + prover.prove(e1, e2, encryptionTable[layer + 1][index1], + encryptionTable[layer + 1][index2], + sw.value, r1, r2); } } - return mixnet; + return new Pair(proofsTable, encryptionTable); } -} +} \ No newline at end of file diff --git a/mixer/src/main/java/mixer/Switch.java b/mixer/src/main/java/mixer/Switch.java new file mode 100644 index 0000000..c52e1fc --- /dev/null +++ b/mixer/src/main/java/mixer/Switch.java @@ -0,0 +1,17 @@ +package mixer; + +/** + * Created by Tzlil on 12/15/2015. + */ +public class Switch{ + + public final int i, j, layer; + public final boolean value; + + public Switch(int i, int j, int layer, boolean value) { + this.i = i; + this.j = j; + this.layer = layer; + this.value = value; + } +} diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 789f323..6c4c002 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -31,12 +31,12 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - boolean switched, + boolean sw, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2) { Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; - if (!switched) + if (!sw) { first = createOrProof(in1, out1, in2, out1, r1, true); second = createOrProof(in1, out1, in1, out2, r1, true); From c8646712c046e26569cce5170916277df0a2fc31 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Thu, 17 Dec 2015 19:15:48 +0200 Subject: [PATCH 07/66] Mixing + Mixer test --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../mixnet/Mix2ZeroKnowledgeProver.java | 2 +- .../src/main/proto/meerkat/mixing.proto | 7 + mixer/src/main/java/main/MainMixing.java | 133 ++++++++++++++++++ mixer/src/main/java/mixer/MixNetwork.java | 32 +---- mixer/src/main/java/mixer/Mixer.java | 4 +- .../main/java/mixer/RandomPermutation.java | 32 +++++ mixer/src/main/java/necessary/Group.java | 14 -- mixer/src/main/java/necessary/GroupImpl.java | 39 ----- mixer/src/main/java/prover/Prover.java | 59 ++++---- mixer/src/main/java/verifier/Verifier.java | 32 ++--- mixer/src/test/java/mixer/MixNetworkTest.java | 45 ++++++ 12 files changed, 276 insertions(+), 125 deletions(-) create mode 100644 mixer/src/main/java/main/MainMixing.java create mode 100644 mixer/src/main/java/mixer/RandomPermutation.java delete mode 100644 mixer/src/main/java/necessary/Group.java delete mode 100644 mixer/src/main/java/necessary/GroupImpl.java create mode 100644 mixer/src/test/java/mixer/MixNetworkTest.java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1e04d9c..31ff232 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Mon Dec 14 14:35:37 IST 2015 +#Thu Dec 17 12:20:25 IST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index a76b5fd..f13a225 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -11,7 +11,7 @@ public interface Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - boolean switched, + boolean switched,int i,int j, int layer, // switch info Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2); diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 763f46b..6a09e12 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -44,8 +44,15 @@ message ZeroKnowledgeProof { bytes z = 15; bytes zTag = 16; } + message Location{ + int32 i = 1; + int32 j = 2; + int32 layer = 3; + } + OrProof first = 1; OrProof second = 2; OrProof third = 3; OrProof fourth = 4; + Location location = 5; } diff --git a/mixer/src/main/java/main/MainMixing.java b/mixer/src/main/java/main/MainMixing.java new file mode 100644 index 0000000..25b61df --- /dev/null +++ b/mixer/src/main/java/main/MainMixing.java @@ -0,0 +1,133 @@ +package main; + +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.Mixer; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import qilin.util.Pair; + +import java.util.Arrays; +import java.util.List; + + +/** + * Created by Tzlil on 12/17/2015. + */ +public class MainMixing { + + Mixer mixer; + Mix2ZeroKnowledgeVerifier verifier; + int n,layers; + + public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n) { + this.mixer = mixer; + this.verifier = verifier; + this.n = n; + this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 + } + + private void firstMixing( ) throws Exception + { + updateBB(mixer.mix(getInputForFirstMixer())); + } + + private void otherMixing() throws Exception + { + List zeroKnowledgeProofsLists = downloadProofs(); + List rerandomizableEncryptedMessageLists = downloadEncryptionTable(); + + for (int i = 0; i < zeroKnowledgeProofsLists.size(); i++) + { + if(!verifyTable(n,layers,zeroKnowledgeProofsLists.get(i),rerandomizableEncryptedMessageLists.get(i))) + throw new Exception(); + } + + Crypto.RerandomizableEncryptedMessage[] lastLayerInCurrent,firstLineInNext; + for (int i = 0; i < rerandomizableEncryptedMessageLists.size() - 1 ; i++) + { + lastLayerInCurrent = rerandomizableEncryptedMessageLists.get(i)[layers - 1]; + firstLineInNext = rerandomizableEncryptedMessageLists.get(i + 1)[0]; + if(!Arrays.equals(lastLayerInCurrent,firstLineInNext)) + throw new Exception(); + } + + List inputForMixer = + Arrays.asList(rerandomizableEncryptedMessageLists + .get(rerandomizableEncryptedMessageLists.size() - 1)[layers - 1]); + + updateBB(mixer.mix(inputForMixer)); + } + + private List downloadProofs() + { + return null; + } + + private List downloadEncryptionTable() + { + return null; + } + + private List getInputForFirstMixer() + { + return null; + } + + private void updateBB(Pair mixerOutput){ + + } + + private boolean verifyTable(int n,int layers, Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs, + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages) + { + int index1,index2,layer; + + //initialize locationChecksum table + // use for check BeneshNet validity + boolean[][] locationChecksum = new boolean[layers][n]; + for (boolean[] locationChecksumLayer: locationChecksum) { + Arrays.fill(locationChecksumLayer,false); + } + + + for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { + for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { + Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + index1 = location.getI(); + index2 = location.getJ(); + layer = location.getLayer(); + + // check location validity + if (layer > layers >> 1) { + if (index2 - index1 != n >> (layers - layer)) + return false; + } + else{ + if (index2 - index1 != n >> (layer + 1)) + return false; + } + + // mark location in table + locationChecksum[layer][index1] = true; + locationChecksum[layer][index2] = true; + + // verify proof + if(!verifier.verify(rerandomizableEncryptedMessages[index1][layer], + rerandomizableEncryptedMessages[index2][layer], + rerandomizableEncryptedMessages[index1][layer + 1], + rerandomizableEncryptedMessages[index2][layer + 1], + zkp)) + return false; + } + } + + // verify all necessary locations for BeneshNet were proved + for (boolean[] checksumLayer: locationChecksum) { + for (boolean locationBoolean: checksumLayer) { + if (!locationBoolean) + return false; + } + } + return true; + } +} diff --git a/mixer/src/main/java/mixer/MixNetwork.java b/mixer/src/main/java/mixer/MixNetwork.java index 219886f..da096d0 100644 --- a/mixer/src/main/java/mixer/MixNetwork.java +++ b/mixer/src/main/java/mixer/MixNetwork.java @@ -1,7 +1,5 @@ package mixer; -import com.google.protobuf.Enum; - import java.util.ArrayList; import java.util.List; import java.util.Queue; @@ -14,12 +12,14 @@ import java.util.Random; public class MixNetwork { private final Switch[][] switches; - private final Random random; - public MixNetwork(int n,int layers,Random random) + public MixNetwork(RandomPermutation randomPermutation) { - this.random = random; - int[] permutation = randomPermutation(n); + int[] permutation = randomPermutation.permutation; + int n = permutation.length; + assert ((n & n-1) == 0); //n == 2^k + int layers = (int)(2*Math.log(n)/Math.log(2)); + int[] pi, piL, piR; Queue permutationsQueue = new ArrayBlockingQueue(n); Graph graph; @@ -64,26 +64,6 @@ public class MixNetwork { return switches[layer]; } - - - private int[] randomPermutation(int n){ - List numbers= new ArrayList(n); - for (int i = 0; i < n; i++) - { - numbers.add(i); - } - - int[] result = new int[n]; - int index; - for (int i = 0; i < n; i++) - { - index = random.nextInt(n - i); - result[i] = numbers.get(index); - numbers.remove(index); - } - return result; - } - private class Graph { private int n; private int nDiv2; diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 97981b7..b39a720 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -42,7 +42,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { EncryptionRandomness r1, r2; RerandomizableEncryptedMessage e1, e2; boolean half = true; - MixNetwork mixNetwork = new MixNetwork(n,layers,random); + MixNetwork mixNetwork = new MixNetwork(new RandomPermutation(n,random)); Switch[] switchesLayer; // set first level of encryption @@ -72,7 +72,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { proofsTable[layer][switchIndex] = prover.prove(e1, e2, encryptionTable[layer + 1][index1], encryptionTable[layer + 1][index2], - sw.value, r1, r2); + sw.value, sw.i,sw.j,sw.layer, r1, r2); } } return new Pair(proofsTable, encryptionTable); diff --git a/mixer/src/main/java/mixer/RandomPermutation.java b/mixer/src/main/java/mixer/RandomPermutation.java new file mode 100644 index 0000000..900761b --- /dev/null +++ b/mixer/src/main/java/mixer/RandomPermutation.java @@ -0,0 +1,32 @@ +package mixer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 12/17/2015. + */ +class RandomPermutation { + + protected final int[] permutation; + + protected RandomPermutation(int n,Random random) + { + List numbers= new ArrayList(n); + for (int i = 0; i < n; i++) + { + numbers.add(i); + } + + int[] result = new int[n]; + int index; + for (int i = 0; i < n; i++) + { + index = random.nextInt(n - i); + result[i] = numbers.get(index); + numbers.remove(index); + } + permutation = result; + } +} diff --git a/mixer/src/main/java/necessary/Group.java b/mixer/src/main/java/necessary/Group.java deleted file mode 100644 index 27c57d8..0000000 --- a/mixer/src/main/java/necessary/Group.java +++ /dev/null @@ -1,14 +0,0 @@ -package necessary; - - -import com.google.protobuf.ByteString; - -import java.math.BigInteger; - -public interface Group { - - ByteString div(ByteString dividend, ByteString divisor); - ByteString mul(ByteString a, ByteString b); - ByteString pow(ByteString bas, BigInteger exp); - BigInteger groupSize(); -} diff --git a/mixer/src/main/java/necessary/GroupImpl.java b/mixer/src/main/java/necessary/GroupImpl.java deleted file mode 100644 index 5e98248..0000000 --- a/mixer/src/main/java/necessary/GroupImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package necessary; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Crypto; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 12/14/2015. - */ -public class GroupImpl implements Group { - - qilin.primitives.Group qilinInstance; - public GroupImpl(qilin.primitives.Group qilinInstance) { - this.qilinInstance = qilinInstance; - } - - - @Override - public ByteString div(ByteString dividend, ByteString divisor) { - return mul(dividend,qilinInstance.negate(divisor)); - } - - @Override - public ByteString mul(ByteString a, ByteString b) { - return qilinInstance.add(a,b); - } - - @Override - public ByteString pow(ByteString bas, BigInteger exp) { - return qilinInstance.multiply(bas,exp); - } - - @Override - public BigInteger groupSize() { - return qilinInstance.orderUpperBound(); - } -} - diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 6c4c002..2de6f29 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -7,20 +7,19 @@ import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import necessary.General; -import necessary.Group; - +import qilin.primitives.Group; import java.math.BigInteger; import java.util.Random; public class Prover implements Mix2ZeroKnowledgeProver { - Group group; + Group group; General general; Random rand; Encryption encryptor; - public Prover(Group group,Random rand,Encryption encryptor,General general) { + public Prover(Group group,Random rand,Encryption encryptor,General general) { this.group = group; this.rand = rand; this.encryptor = encryptor; @@ -31,7 +30,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - boolean sw, + boolean sw,int i,int j, int layer, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2) { @@ -50,11 +49,17 @@ public class Prover implements Mix2ZeroKnowledgeProver { third = createOrProof(in2, out1, in2, out2, r2, true); fourth = createOrProof(in1, out2, in2, out2, r1, true); } + Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() + .setI(i) + .setJ(j) + .setLayer(layer) + .build(); return Mixing.ZeroKnowledgeProof.newBuilder() .setFirst(first) .setSecond(second) .setThird(third) .setFourth(fourth) + .setLocation(location) .build(); } @@ -74,6 +79,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,x,flag); } + + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalCiphertext e1, ElGamalCiphertext e2, ElGamalCiphertext e1New, @@ -81,27 +88,27 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.EncryptionRandomness x, boolean flag) { ByteString g1 = general.getG(); - ByteString h1 = group.div(e1New.getC1(),e1.getC1()); + ByteString h1 = group.add(e1New.getC1(),group.negate(e1.getC1())); ByteString g2 = general.getH(); - ByteString h2 = group.div(e1New.getC2(),e1.getC2()); + ByteString h2 = group.add(e1New.getC2(),group.negate(e1.getC2())); ByteString g1Tag = general.getG(); - ByteString h1Tag = group.div(e2New.getC1(),e2.getC1()); + ByteString h1Tag = group.add(e2New.getC1(),group.negate(e2.getC1())); ByteString g2Tag = general.getH(); - ByteString h2Tag = group.div(e2New.getC2(),e2.getC2()); + ByteString h2Tag = group.add(e2New.getC2(),group.negate(e2.getC2())); - BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); BigInteger c1,c2,z,zTag; ByteString u,v,uTag,vTag; if (flag) { - c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); - zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); //step 1 - u = group.pow(g1, r); - v = group.pow(g2, r); - uTag = group.div(group.pow(g1Tag, zTag), group.pow(h1Tag, c2)); - vTag = group.div(group.pow(g2Tag, zTag), group.pow(h2Tag, c2)); + u = group.multiply(g1, r); + v = group.multiply(g2, r); + uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); + vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); //step 2 // c1 = (hash(input + step1) + group size - c2)% group size Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = @@ -119,20 +126,20 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setUTag(uTag) .setVTag(vTag) .build(); - c1 = general.hash(forRandomOracle).add(group.groupSize().subtract(c2)).mod(group.groupSize()); + c1 = general.hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); //step 3 //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.groupSize()); + z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); } else { - c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); - z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.groupSize()); + c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); //step 1 - uTag = group.pow(g1Tag, r); - vTag = group.pow(g2Tag, r); - u = group.div(group.pow(g1, z), group.pow(h1, c1)); - v = group.div(group.pow(g2, z), group.pow(h2, c1)); + uTag = group.multiply(g1Tag, r); + vTag = group.multiply(g2Tag, r); + u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); + v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); //step 2 // c1 = (hash(input + step1) + group size - c1)% group size Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = @@ -150,10 +157,10 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setUTag(uTag) .setVTag(vTag) .build(); - c2 = general.hash(forRandomOracle).add(group.groupSize().subtract(c1)).mod(group.groupSize()); + c2 = general.hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); //step 3 //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.groupSize()); + zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); } return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() .setG1(g1) diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index 197e012..d70bd91 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -1,12 +1,11 @@ package verifier; -import meerkat.crypto.Encryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import necessary.General; -import necessary.Group; +import qilin.primitives.Group; import java.math.BigInteger; @@ -42,6 +41,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { ElGamalCiphertext e1TagElGamal = general.calcRerandomizable2ElGamal(out1); ElGamalCiphertext e2TagElGamal = general.calcRerandomizable2ElGamal(out2); + return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getFirst()) && verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getSecond()) && verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getThird()) && @@ -73,28 +73,28 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { return //input orProof.getG1().equals(general.getG())&& - orProof.getH1().equals(group.div(e1New.getC1(), e1.getC1()))&& + orProof.getH1().equals(group.add(e1New.getC1(), group.negate(e1.getC1())))&& orProof.getG2().equals(general.getH())&& - orProof.getH2().equals(group.div(e1New.getC2(), e1.getC2()))&& + orProof.getH2().equals(group.add(e1New.getC2(), group.negate(e1.getC2())))&& // input' orProof.getG1Tag().equals(general.getG())&& - orProof.getH1Tag().equals(group.div(e2New.getC1(), e2.getC1()))&& + orProof.getH1Tag().equals(group.add(e2New.getC1(), group.negate(e2.getC1())))&& orProof.getG2Tag().equals(general.getH())&& - orProof.getH2Tag().equals(group.div(e2New.getC2(), e2.getC2())) && + orProof.getH2Tag().equals(group.add(e2New.getC2(), group.negate(e2.getC2()))) && // hash // assert (c1 + c2 ) % group size == hash (imput + step1) % group size - new BigInteger(orProof.getC1().toByteArray()).add(new BigInteger(orProof.getC2().toByteArray())).mod(group.groupSize()) - .equals(general.hash(forRandomOracle).mod(group.groupSize()).mod(group.groupSize()))&& + new BigInteger(orProof.getC1().toByteArray()).add(new BigInteger(orProof.getC2().toByteArray())).mod(group.orderUpperBound()) + .equals(general.hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()))&& // proof // g1 ^ z == u * ( h1 ^ c1 ) && g2 ^ z == v * ( h2 ^ c1 ) && the same for tag case - group.pow(orProof.getG1(), new BigInteger(orProof.getZ().toByteArray())) - .equals(group.mul(orProof.getU(), group.pow(orProof.getH1(),new BigInteger(orProof.getC1().toByteArray())))) && - group.pow(orProof.getG2(), new BigInteger(orProof.getZ().toByteArray())) - .equals(group.mul(orProof.getV(), group.pow(orProof.getH2(),new BigInteger(orProof.getC1().toByteArray())))) && - group.pow(orProof.getG1Tag(), new BigInteger(orProof.getZTag().toByteArray())) - .equals(group.mul(orProof.getUTag(), group.pow(orProof.getH1Tag(),new BigInteger(orProof.getC2().toByteArray())))) && - group.pow(orProof.getG2Tag(), new BigInteger(orProof.getZTag().toByteArray())) - .equals(group.mul(orProof.getVTag(), group.pow(orProof.getH2Tag(),new BigInteger(orProof.getC2().toByteArray())))); + group.multiply(orProof.getG1(), new BigInteger(orProof.getZ().toByteArray())) + .equals(group.add(orProof.getU(), group.multiply(orProof.getH1(),new BigInteger(orProof.getC1().toByteArray())))) && + group.multiply(orProof.getG2(), new BigInteger(orProof.getZ().toByteArray())) + .equals(group.add(orProof.getV(), group.multiply(orProof.getH2(),new BigInteger(orProof.getC1().toByteArray())))) && + group.multiply(orProof.getG1Tag(), new BigInteger(orProof.getZTag().toByteArray())) + .equals(group.add(orProof.getUTag(), group.multiply(orProof.getH1Tag(),new BigInteger(orProof.getC2().toByteArray())))) && + group.multiply(orProof.getG2Tag(), new BigInteger(orProof.getZTag().toByteArray())) + .equals(group.add(orProof.getVTag(), group.multiply(orProof.getH2Tag(),new BigInteger(orProof.getC2().toByteArray())))); } } diff --git a/mixer/src/test/java/mixer/MixNetworkTest.java b/mixer/src/test/java/mixer/MixNetworkTest.java new file mode 100644 index 0000000..b783a2a --- /dev/null +++ b/mixer/src/test/java/mixer/MixNetworkTest.java @@ -0,0 +1,45 @@ +package mixer; + +/** + * Created by Tzlil on 12/17/2015. + */ + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Random; + +public class MixNetworkTest { + + @Test + public void testMixNetwork() throws Exception{ + + Random random = new Random(); + int logn = random.nextInt()%10 + 5; + + int n = 1 << logn; + int layers = 2*logn - 1; + RandomPermutation randomPermutation = new RandomPermutation(n,random); + MixNetwork mixNetwork = new MixNetwork(randomPermutation); + + //initialize arr s.t arr[i] = i + int[] arr = new int[n]; + for (int i = 0; i < n ;i ++) + arr[i] = i; + + // layer by layer swap between values + for (int layer = 0 ; layer< layers ; layer ++) { + for (Switch sw : mixNetwork.getSwitchesByLayer(layer)) { + if(sw.value) { + arr[sw.i] += arr[sw.j]; + arr[sw.j] = arr[sw.i] - arr[sw.j]; + arr[sw.i] -= arr[sw.j]; + } + } + } + + assert(Arrays.equals(arr,randomPermutation.permutation)); + + } + +} From be6449f27d03be62a8afdcb87c33d8a8c26cf6d6 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Thu, 17 Dec 2015 23:45:32 +0200 Subject: [PATCH 08/66] before merge with master --- mixer/src/main/java/mixer/MixNetwork.java | 6 +++--- mixer/src/test/java/mixer/MixNetworkTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mixer/src/main/java/mixer/MixNetwork.java b/mixer/src/main/java/mixer/MixNetwork.java index da096d0..833ef73 100644 --- a/mixer/src/main/java/mixer/MixNetwork.java +++ b/mixer/src/main/java/mixer/MixNetwork.java @@ -18,7 +18,7 @@ public class MixNetwork { int[] permutation = randomPermutation.permutation; int n = permutation.length; assert ((n & n-1) == 0); //n == 2^k - int layers = (int)(2*Math.log(n)/Math.log(2)); + int layers = (int)(2*Math.log(n)/Math.log(2)) - 1; int[] pi, piL, piR; Queue permutationsQueue = new ArrayBlockingQueue(n); @@ -40,8 +40,8 @@ public class MixNetwork { piR = new int[iDiv2]; for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j { - index1 = k + j; - index2 = k + j + iDiv2; + index1 = k + (j << 1); + index2 = index1 + iDiv2; switches[layers - layer - 1][k + j] = new Switch(index1,index2,layers - layer - 1,graph.getSwitchValue(k, true)); switches[layer][k + j] = new Switch(index1,index2,layer,graph.getSwitchValue(k, false)); diff --git a/mixer/src/test/java/mixer/MixNetworkTest.java b/mixer/src/test/java/mixer/MixNetworkTest.java index b783a2a..4652460 100644 --- a/mixer/src/test/java/mixer/MixNetworkTest.java +++ b/mixer/src/test/java/mixer/MixNetworkTest.java @@ -15,7 +15,7 @@ public class MixNetworkTest { public void testMixNetwork() throws Exception{ Random random = new Random(); - int logn = random.nextInt()%10 + 5; + int logn = 10; int n = 1 << logn; int layers = 2*logn - 1; From 75c411a5e73de543d1778214ecf1452dafd23eda Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 27 Dec 2015 13:12:17 +0200 Subject: [PATCH 09/66] integrated to AsyncBBClient --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../main/proto/meerkat/BulletinBoardAPI.proto | 50 ++- .../src/main/proto/meerkat/voting.proto | 12 + mixer/src/main/java/main/MainMixing.java | 331 +++++++++++++----- .../necessary/AsyncBulletinBoardClient.java | 62 ++++ .../java/necessary/BulletinBoardClient.java | 63 ++++ .../src/main/java/necessary/SignedBatch.java | 54 +++ 7 files changed, 468 insertions(+), 106 deletions(-) create mode 100644 mixer/src/main/java/necessary/AsyncBulletinBoardClient.java create mode 100644 mixer/src/main/java/necessary/BulletinBoardClient.java create mode 100644 mixer/src/main/java/necessary/SignedBatch.java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 31ff232..b99caa4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Thu Dec 17 12:20:25 IST 2015 +#Sun Dec 27 09:28:01 IST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 28fc948..2e2e7e2 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -10,6 +10,9 @@ message BoolMsg { bool value = 1; } +message IntMsg { + int32 value = 1; +} message MessageID { // The ID of a message for unique retrieval. @@ -26,10 +29,10 @@ message UnsignedBulletinBoardMessage { } message BulletinBoardMessage { - + // Serial entry number of message in database int64 entryNum = 1; - + // Unsigned raw data of message UnsignedBulletinBoardMessage msg = 2; @@ -38,9 +41,9 @@ message BulletinBoardMessage { } message BulletinBoardMessageList { - + repeated BulletinBoardMessage message = 1; - + } enum FilterType { @@ -49,13 +52,17 @@ enum FilterType { MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological) SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer) TAG = 4; // Find all entries in database that have a specific tag + + // NOTE: The MAX_MESSAGES filter must remain the last filter type + // This is because the condition it specifies in an SQL statement must come last in the statement + // Keeping it last here allows for easily sorting the filters and keeping the code general MAX_MESSAGES = 5; // Return at most some specified number of messages } message MessageFilter { - + FilterType type = 1; - + oneof filter{ bytes id = 2; int64 entry = 3; @@ -65,9 +72,36 @@ message MessageFilter { } message MessageFilterList { - + // Combination of filters. // To be implemented using intersection ("AND") operations. repeated MessageFilter filter = 1; - + +} + +// This message is used to start a batch transfer to the Bulletin Board Server +message BeginBatchMessage { + bytes signerId = 1; // Unique signer identifier + int32 batchId = 2; // Unique identifier for the batch (unique per signer) + repeated string tag = 3; // Tags for the batch message +} + +// This message is used to finalize and sign a batch transfer to the Bulletin Board Server +message CloseBatchMessage { + int32 batchId = 1; // Unique identifier for the batch (unique per signer) + int32 batchLength = 2; // Number of messages in the batch + meerkat.Signature sig = 3; // Signature on the (ordered) batch messages +} + +// Container for single batch message data +message BatchData { + bytes data = 1; +} + +// These messages comprise a batch message +message BatchMessage { + bytes signerId = 1; // Unique signer identifier + int32 batchId = 2; // Unique identifier for the batch (unique per signer) + int32 serialNum = 3; // Location of the message in the batch: starting from 0 + BatchData data = 4; // Actual data } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index beb4e0c..9837cce 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -52,6 +52,16 @@ message BallotAnswerTranslationTable { bytes data = 1; } +// Data required in order to access the Bulletin Board Servers +message BulletinBoardClientParams { + + // Addresses of all Bulletin Board Servers + repeated string bulletinBoardAddress = 1; + + // Threshold fraction of successful servers posts before a post task is considered complete + float minRedundancy = 2; +} + message ElectionParams { // TODO: different sets of keys for different roles? repeated SignatureVerificationKey trusteeVerificationKeys = 1; @@ -75,4 +85,6 @@ message ElectionParams { // Translation table between answers and plaintext encoding BallotAnswerTranslationTable answerTranslationTable = 7; + // Data required in order to access the Bulletin Board Servers + BulletinBoardClientParams bulletinBoardClientParams = 8; } diff --git a/mixer/src/main/java/main/MainMixing.java b/mixer/src/main/java/main/MainMixing.java index 25b61df..70423c5 100644 --- a/mixer/src/main/java/main/MainMixing.java +++ b/mixer/src/main/java/main/MainMixing.java @@ -1,11 +1,20 @@ package main; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.crypto.mixnet.Mixer; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; +import necessary.AsyncBulletinBoardClient; +import necessary.BulletinBoardClient; +import necessary.SignedBatch; import qilin.util.Pair; + +import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -15,119 +24,247 @@ import java.util.List; */ public class MainMixing { - Mixer mixer; - Mix2ZeroKnowledgeVerifier verifier; - int n,layers; + private Mixer mixer; + private Mix2ZeroKnowledgeVerifier verifier; + private int n, layers; + private AsyncBulletinBoardClient asyncBulletinBoardClient; + private final byte[] id; + private final int mixerOrder; - public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n) { + + public MainMixing(Mixer mixer, int mixerOrder, Mix2ZeroKnowledgeVerifier verifier, int n + , AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) { this.mixer = mixer; + this.mixerOrder = mixerOrder; this.verifier = verifier; this.n = n; this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 + this.asyncBulletinBoardClient = asyncBulletinBoardClient; + this.id = id; } - private void firstMixing( ) throws Exception - { - updateBB(mixer.mix(getInputForFirstMixer())); - } + public void main(List prevBatchIds, int batchId, BulletinBoardClient.ClientCallback callback) throws Exception { - private void otherMixing() throws Exception - { - List zeroKnowledgeProofsLists = downloadProofs(); - List rerandomizableEncryptedMessageLists = downloadEncryptionTable(); - - for (int i = 0; i < zeroKnowledgeProofsLists.size(); i++) - { - if(!verifyTable(n,layers,zeroKnowledgeProofsLists.get(i),rerandomizableEncryptedMessageLists.get(i))) - throw new Exception(); - } - - Crypto.RerandomizableEncryptedMessage[] lastLayerInCurrent,firstLineInNext; - for (int i = 0; i < rerandomizableEncryptedMessageLists.size() - 1 ; i++) - { - lastLayerInCurrent = rerandomizableEncryptedMessageLists.get(i)[layers - 1]; - firstLineInNext = rerandomizableEncryptedMessageLists.get(i + 1)[0]; - if(!Arrays.equals(lastLayerInCurrent,firstLineInNext)) - throw new Exception(); - } - - List inputForMixer = - Arrays.asList(rerandomizableEncryptedMessageLists - .get(rerandomizableEncryptedMessageLists.size() - 1)[layers - 1]); - - updateBB(mixer.mix(inputForMixer)); - } - - private List downloadProofs() - { - return null; - } - - private List downloadEncryptionTable() - { - return null; - } - - private List getInputForFirstMixer() - { - return null; - } - - private void updateBB(Pair mixerOutput){ - - } - - private boolean verifyTable(int n,int layers, Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs, - Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages) - { - int index1,index2,layer; - - //initialize locationChecksum table - // use for check BeneshNet validity - boolean[][] locationChecksum = new boolean[layers][n]; - for (boolean[] locationChecksumLayer: locationChecksum) { - Arrays.fill(locationChecksumLayer,false); - } + List mixerInput; - for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { - for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { - Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); - index1 = location.getI(); - index2 = location.getJ(); - layer = location.getLayer(); + if (mixerOrder > 0) { + List batchHandlers = new ArrayList(prevBatchIds.size()); + BatchHandler currentBatchHandler; + for (Integer prevBatchId : prevBatchIds) { + currentBatchHandler = new BatchHandler(n, layers); + asyncBulletinBoardClient.readBatch(id, prevBatchId, currentBatchHandler); + batchHandlers.add(currentBatchHandler); + } - // check location validity - if (layer > layers >> 1) { - if (index2 - index1 != n >> (layers - layer)) - return false; + boolean allDone = false; + while (!allDone) { + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing } - else{ - if (index2 - index1 != n >> (layer + 1)) - return false; + // check all handlers done + allDone = true; + for (BatchHandler batchHandler : batchHandlers) { + allDone &= batchHandler.done; } - - // mark location in table - locationChecksum[layer][index1] = true; - locationChecksum[layer][index2] = true; - - // verify proof - if(!verifier.verify(rerandomizableEncryptedMessages[index1][layer], - rerandomizableEncryptedMessages[index2][layer], - rerandomizableEncryptedMessages[index1][layer + 1], - rerandomizableEncryptedMessages[index2][layer + 1], - zkp)) - return false; + } + + // assert all handlers succeeded + for (BatchHandler batchHandler : batchHandlers) { + if(batchHandler.e != null) + throw batchHandler.e; + } + + BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); + mixerInput = lastBatchHandler.getInputForMixer(); + + } else { + // ToDo : handle first mixer case + mixerInput = null; + } + + Pair mixerOutput + = mixer.mix(mixerInput); + updateBB(mixerOutput, batchId, callback); + + } + + + private void updateBB(Pair mixerOutput + , int batchId, BulletinBoardClient.ClientCallback callback) { + + BatchConverter batchConverter = new BatchConverter(); + List batchDataList = batchConverter.mixerOutput2BatchData(mixerOutput); + asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); + } + + private class BatchConverter { + + ByteString IntegerToByteString(int a){ + return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); + } + + int ByteString2Integer(ByteString bs) { + return Integer.valueOf(bs.toString()); + } + + List mixerOutput2BatchData + (Pair mixerOutput) { + + List result = new ArrayList(); + + // + + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(IntegerToByteString(n)) + .build()); + + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.a) { + for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(zkp.toByteString()) + .build()); + } + } + for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.b) { + for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(encryption.toByteString()) + .build()); + } + } + return result; + } + Pair batchDataList2MixerOutput + (List batchDataList) throws Exception { + + if (n != ByteString2Integer(batchDataList.remove(0).getData())){ + throw new Exception(); + } + + int nDiv2 = n >>1; + Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; + for (int layer = 0; layer (proofs,encryptions); + + } + + } + + + + private class BatchHandler implements BulletinBoardClient.ClientCallback { + + public Pair mixerOutput; + public boolean done; + private int n,layers; + private Exception e; + + public BatchHandler(int n, int layers) { + this.n = n; + this.layers = layers; + done = false; + e = null; + } + + // convert batch message to MixerInput + // and verify it + @Override + public void handleCallback(SignedBatch msg) { + BatchConverter batchConverter = new BatchConverter(); + try { + mixerOutput = batchConverter.batchDataList2MixerOutput(msg.getBatchDataList()); + done = verifyTable(); + } catch (Exception e) { + this.e = e; + done = true; } } - // verify all necessary locations for BeneshNet were proved - for (boolean[] checksumLayer: locationChecksum) { - for (boolean locationBoolean: checksumLayer) { - if (!locationBoolean) - return false; - } + @Override + public void handleFailure(Throwable t) { + + } + + private boolean verifyTable() + { + int index1,index2,layer; + + //initialize locationChecksum table + // use for check BeneshNet validity + boolean[][] locationChecksum = new boolean[layers][n]; + for (boolean[] locationChecksumLayer: locationChecksum) { + Arrays.fill(locationChecksumLayer,false); + } + + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.a; + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.b; + + for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { + for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { + Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + index1 = location.getI(); + index2 = location.getJ(); + layer = location.getLayer(); + + // check location validity + if (layer > layers >> 1) { + if (index2 - index1 != n >> (layers - layer)) + return false; + } + else{ + if (index2 - index1 != n >> (layer + 1)) + return false; + } + + // mark location in table + locationChecksum[layer][index1] = true; + locationChecksum[layer][index2] = true; + + // verify proof + if(!verifier.verify(rerandomizableEncryptedMessages[index1][layer], + rerandomizableEncryptedMessages[index2][layer], + rerandomizableEncryptedMessages[index1][layer + 1], + rerandomizableEncryptedMessages[index2][layer + 1], + zkp)) + return false; + } + } + + // verify all necessary locations for BeneshNet were proved + for (boolean[] checksumLayer: locationChecksum) { + for (boolean locationBoolean: checksumLayer) { + if (!locationBoolean) + return false; + } + } + return true; + } + + public List getInputForMixer() + { + return Arrays.asList(mixerOutput.b[mixerOutput.b.length - 1]); } - return true; } + } diff --git a/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java new file mode 100644 index 0000000..b8847f9 --- /dev/null +++ b/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java @@ -0,0 +1,62 @@ +package necessary; + + import meerkat.protobuf.BulletinBoardAPI.*; + + import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 14-Dec-15. + */ +public interface AsyncBulletinBoardClient extends BulletinBoardClient { + + /** + * Post a message to the bulletin board in an asynchronous manner + * @param msg is the message to be posted + * @param callback is a class containing methods to handle the result of the operation + * @return a unique message ID for the message, that can be later used to retrieve the batch + */ + MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + + /** + * This method allows for sending large messages as a batch to the bulletin board + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param batchDataList is the (canonically ordered) list of data comprising the batch message + * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) + * @param callback is a callback function class for handling results of the operation + * @return a unique message ID for the entire message, that can be later used to retrieve the batch + */ + MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatch method in which startPosition is set to the default value 0 + */ + MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + + /** + * Check how "safe" a given message is in an asynchronous manner + * The result of the computation is a rank between 0.0 and 1.0 indicating the fraction of servers containing the message + * @param id is the unique message identifier for retrieval + * @param callback is a callback function class for handling results of the operation + */ + void getRedundancy(MessageID id, ClientCallback callback); + + /** + * Read all messages posted matching the given filter in an asynchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @param callback is a callback function class for handling results of the operation + */ + void readMessages(MessageFilterList filterList, ClientCallback> callback); + + /** + * Read a given batch message from the bulletin board + * @param signerId is the ID of the signer (sender) of the batch message + * @param batchId is the unique (per signer) ID of the batch + * @param callback is a callback class for handling the result of the operation + */ + void readBatch(byte[] signerId, int batchId, ClientCallback callback); + +} diff --git a/mixer/src/main/java/necessary/BulletinBoardClient.java b/mixer/src/main/java/necessary/BulletinBoardClient.java new file mode 100644 index 0000000..6442c40 --- /dev/null +++ b/mixer/src/main/java/necessary/BulletinBoardClient.java @@ -0,0 +1,63 @@ +package necessary; + +/** + * Created by Tzlil on 12/27/2015. + */ + + import meerkat.comm.CommunicationException; + import meerkat.protobuf.Voting.*; + + import static meerkat.protobuf.BulletinBoardAPI.*; + + import java.util.List; + +/** + * Created by talm on 24/10/15. + */ +public interface BulletinBoardClient { + + interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + /** + * Initialize the client to use some specified servers + * @param clientParams contains the parameters required for the client setup + */ + void init(BulletinBoardClientParams clientParams); + + /** + * Post a message to the bulletin board in a synchronous manner + * @param msg is the message to be posted + * @return a unique message ID for the message, that can be later used to retrieve the batch + * @throws CommunicationException + */ + MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; + + + + /** + * Check how "safe" a given message is in a synchronous manner + * @param id is the unique message identifier for retrieval + * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) + */ + float getRedundancy(MessageID id); + + /** + * Read all messages posted matching the given filter in a synchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @return the list of messages + */ + List readMessages(MessageFilterList filterList); + + /** + * Closes all connections, if any. + * This is done in a synchronous (blocking) way. + */ + void close(); + +} diff --git a/mixer/src/main/java/necessary/SignedBatch.java b/mixer/src/main/java/necessary/SignedBatch.java new file mode 100644 index 0000000..6aecebf --- /dev/null +++ b/mixer/src/main/java/necessary/SignedBatch.java @@ -0,0 +1,54 @@ +package necessary; + +/** + * Created by Tzlil on 12/27/2015. + */ + + import meerkat.protobuf.BulletinBoardAPI.*; + import meerkat.protobuf.Crypto.*; + + import java.util.LinkedList; + import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * A data structure for holding both a batch message and its signature + */ +public class SignedBatch { + + private List batchDataList; + private Signature signature; + + public SignedBatch() { + batchDataList = new LinkedList(); + } + + public SignedBatch(List newDataList) { + this(); + appendBatchData(newDataList); + } + + public SignedBatch(List newDataList, Signature newSignature) { + this(newDataList); + signature = newSignature; + } + + public List getBatchDataList() { + return batchDataList; + } + + public Signature getSignature() { + return signature; + } + + public void appendBatchData(BatchData newBatchData) { + batchDataList.add(newBatchData); + } + + public void appendBatchData(List newBatchDataList) { + batchDataList.addAll(newBatchDataList); + } + + +} From 026a879de3759d05fa081446abd7bd9780628c15 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Thu, 31 Dec 2015 18:58:25 +0200 Subject: [PATCH 10/66] zkp verification fails from time to time --- .../crypto/concrete/ECElGamalEncryption.java | 9 + .../mixnet/Mix2ZeroKnowledgeProver.java | 3 +- .../mixnet/Mix2ZeroKnowledgeVerifier.java | 3 +- .../src/main/proto/meerkat/mixing.proto | 4 + .../crypto/concrete/ECElGamalUtils.java | 2 +- mixer/src/main/java/main/MainMixing.java | 3 +- mixer/src/main/java/mixer/Mixer.java | 10 +- mixer/src/main/java/mixer/Switch.java | 11 + mixer/src/main/java/necessary/General.java | 25 -- .../src/main/java/necessary/GeneralImpl.java | 46 ---- .../src/main/java/prover/ProofOrganizer.java | 76 ++++++ mixer/src/main/java/prover/Prover.java | 236 ++++++++++++------ mixer/src/main/java/verifier/Verifier.java | 194 +++++++++++--- mixer/src/main/java/verifier/VerifyTable.java | 83 ++++++ mixer/src/test/java/mixer/MixingText.java | 113 +++++++++ 15 files changed, 627 insertions(+), 191 deletions(-) delete mode 100644 mixer/src/main/java/necessary/General.java delete mode 100644 mixer/src/main/java/necessary/GeneralImpl.java create mode 100644 mixer/src/main/java/prover/ProofOrganizer.java create mode 100644 mixer/src/main/java/verifier/VerifyTable.java create mode 100644 mixer/src/test/java/mixer/MixingText.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index c281dd7..910a1aa 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -109,6 +109,15 @@ public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption .build(); } + public static ConcreteCrypto.ElGamalCiphertext rerandomizableEncryptedMessage2ElGamalCiphertext(Crypto.RerandomizableEncryptedMessage msg) throws InvalidProtocolBufferException { + return ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); + } + + public static Crypto.RerandomizableEncryptedMessage elGamalCiphertext2RerandomizableEncryptedMessage(ConcreteCrypto.ElGamalCiphertext msg) { + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData(msg.toByteString()).build(); + } + @Override public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index f13a225..487483e 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -1,5 +1,6 @@ package meerkat.crypto.mixnet; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -13,7 +14,7 @@ public interface Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage out2, boolean switched,int i,int j, int layer, // switch info Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2); + Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java index dd3c251..f98f0ac 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java @@ -1,5 +1,6 @@ package meerkat.crypto.mixnet; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -19,5 +20,5 @@ public interface Mix2ZeroKnowledgeVerifier { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof); + Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 6a09e12..83c87d6 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -6,6 +6,10 @@ option java_package = "meerkat.protobuf"; import 'meerkat/crypto.proto'; +message Plaintext{ + bytes data = 1; +} + message ZeroKnowledgeProof { message OrProof { message ForRandomOracle{ diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java index fec4803..425ec50 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java @@ -49,7 +49,7 @@ public class ECElGamalUtils { .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); return serializedPk; - } catch (NoSuchAlgorithmException|InvalidKeySpecException e) { + } catch (Exception e) { logger.error("Should never happen!", e); throw new RuntimeException("Error converting public key!", e); } diff --git a/mixer/src/main/java/main/MainMixing.java b/mixer/src/main/java/main/MainMixing.java index 70423c5..ab832d7 100644 --- a/mixer/src/main/java/main/MainMixing.java +++ b/mixer/src/main/java/main/MainMixing.java @@ -206,8 +206,7 @@ public class MainMixing { } - private boolean verifyTable() - { + private boolean verifyTable() throws InvalidProtocolBufferException { int index1,index2,layer; //initialize locationChecksum table diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index b39a720..1de3a91 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -2,6 +2,8 @@ package mixer; import java.util.ArrayList; import java.util.List; + +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import qilin.util.Pair; import java.util.Random; @@ -12,20 +14,23 @@ import meerkat.protobuf.Mixing.*; import meerkat.crypto.Encryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import verifier.Verifier; public class Mixer implements meerkat.crypto.mixnet.Mixer { private Random random; private Mix2ZeroKnowledgeProver prover; private Encryption encryptor; + private Mix2ZeroKnowledgeVerifier verifier; public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc) { this.random = rand; this.prover = prov; this.encryptor = enc; - + this.verifier = null; } + public Pair mix(List ciphertexts) throws InvalidProtocolBufferException { int n = ciphertexts.size(); @@ -50,6 +55,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { encryptionTable[0][j] = ciphertexts.get(j); } + // main loop for (int layer = 0; layer < layers; layer++) { @@ -73,6 +79,8 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { prover.prove(e1, e2, encryptionTable[layer + 1][index1], encryptionTable[layer + 1][index2], sw.value, sw.i,sw.j,sw.layer, r1, r2); + + switchIndex = (switchIndex + 1) % nDiv2; } } return new Pair(proofsTable, encryptionTable); diff --git a/mixer/src/main/java/mixer/Switch.java b/mixer/src/main/java/mixer/Switch.java index c52e1fc..a7401ff 100644 --- a/mixer/src/main/java/mixer/Switch.java +++ b/mixer/src/main/java/mixer/Switch.java @@ -14,4 +14,15 @@ public class Switch{ this.layer = layer; this.value = value; } + + + @Override + public String toString() { + return "Switch{" + + "i=" + i + + ", j=" + j + + ", layer=" + layer + + ", value=" + value + + '}'; + } } diff --git a/mixer/src/main/java/necessary/General.java b/mixer/src/main/java/necessary/General.java deleted file mode 100644 index 92df602..0000000 --- a/mixer/src/main/java/necessary/General.java +++ /dev/null @@ -1,25 +0,0 @@ -package necessary; - -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Mixing; - -import java.math.BigInteger; - -public interface General { - - /* - given RerandomizableEncryptedMessage returns an equivalent ElGamalCiphertext - */ - ConcreteCrypto.ElGamalCiphertext calcRerandomizable2ElGamal(Crypto.RerandomizableEncryptedMessage enc); - - ByteString getG(); - ByteString getH(); - - /* - fiat shamir assumption - */ - BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input); -} diff --git a/mixer/src/main/java/necessary/GeneralImpl.java b/mixer/src/main/java/necessary/GeneralImpl.java deleted file mode 100644 index 9a4fda6..0000000 --- a/mixer/src/main/java/necessary/GeneralImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package necessary; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; -import qilin.primitives.RandomOracle; -import java.math.BigInteger; - -/** - * Created by Tzlil on 12/14/2015. - */ -public class GeneralImpl implements General { - - - private final RandomOracle rndomOracle; - private final ByteString h; - private final ByteString g; - - public GeneralImpl(RandomOracle randomOracle,ByteString g,ByteString h) { - this.rndomOracle = randomOracle; - this.h = h; - this.g = g; - } - - @Override - public ConcreteCrypto.ElGamalCiphertext calcRerandomizable2ElGamal(Crypto.RerandomizableEncryptedMessage enc) { - return null; - } - - @Override - public ByteString getG() { - return g; - } - - @Override - public ByteString getH() { - return h; - } - - @Override - public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { - byte[] arr = input.toByteArray(); - return new BigInteger(this.rndomOracle.hash(arr,arr.length)); - } -} diff --git a/mixer/src/main/java/prover/ProofOrganizer.java b/mixer/src/main/java/prover/ProofOrganizer.java new file mode 100644 index 0000000..3dae29c --- /dev/null +++ b/mixer/src/main/java/prover/ProofOrganizer.java @@ -0,0 +1,76 @@ +package prover; + +import meerkat.protobuf.Crypto; + +/** + * Created by Tzlil on 12/30/2015. + */ +public class ProofOrganizer { + + private final Crypto.RerandomizableEncryptedMessage e1; + private final Crypto.RerandomizableEncryptedMessage e2; + private final Crypto.RerandomizableEncryptedMessage e1New; + private final Crypto.RerandomizableEncryptedMessage e2New; + + //in1, out1, in2, out1, + //in1, out1, in1, out2 + //in2, out1, in2, out2, + //in1, out2, in2, out2 + public ProofOrganizer(Crypto.RerandomizableEncryptedMessage e1,Crypto.RerandomizableEncryptedMessage e2 + ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New) + { + this.e1 = e1; + this.e2 = e2; + this.e1New = e1New; + this.e2New = e2New; + + } + + public enum OrProofOrder{ + first,second,third,fourth + } + + public Crypto.RerandomizableEncryptedMessage getE1(OrProofOrder orProofOrder) + { + switch (orProofOrder){ + case third: + return e2; + default: + return e1; + } + + } + + public Crypto.RerandomizableEncryptedMessage getE1New(OrProofOrder orProofOrder) + { + switch (orProofOrder){ + case fourth: + return e2New; + default: + return e1New; + } + + } + + public Crypto.RerandomizableEncryptedMessage getE2(OrProofOrder orProofOrder) + { + switch (orProofOrder){ + case second: + return e1; + default: + return e2; + } + + } + + public Crypto.RerandomizableEncryptedMessage getE2New(OrProofOrder orProofOrder) + { + switch (orProofOrder){ + case first: + return e1New; + default: + return e2New; + } + + } +} diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 2de6f29..7712a41 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -1,66 +1,135 @@ package prover; import com.google.protobuf.ByteString; -import meerkat.crypto.Encryption; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import necessary.General; -import qilin.primitives.Group; +import org.bouncycastle.math.ec.ECPoint; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; public class Prover implements Mix2ZeroKnowledgeProver { - Group group; - General general; + ECGroup group; + RandomOracle randomOracle; Random rand; - Encryption encryptor; + ECElGamalEncryption ecElGamalEncryption; + ECPoint g,h; + + Mix2ZeroKnowledgeVerifier verifier; + + public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { - public Prover(Group group,Random rand,Encryption encryptor,General general) { - this.group = group; this.rand = rand; - this.encryptor = encryptor; - this.general = general; + this.ecElGamalEncryption = encryptor; + this.randomOracle = randomOracle; + this.group = ecElGamalEncryption.getGroup(); + this.g = group.getGenerator(); + this.h = ecElGamalEncryption.getElGamalPK().getPK(); + + verifier = null; } + public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle,Mix2ZeroKnowledgeVerifier verifier) { + + this.rand = rand; + this.ecElGamalEncryption = encryptor; + this.randomOracle = randomOracle; + this.group = ecElGamalEncryption.getGroup(); + this.g = group.getGenerator(); + this.h = ecElGamalEncryption.getElGamalPK().getPK(); + + this.verifier = verifier; + } + + + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, boolean sw,int i,int j, int layer, Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2) { + Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; + ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2); if (!sw) { - first = createOrProof(in1, out1, in2, out1, r1, true); - second = createOrProof(in1, out1, in1, out2, r1, true); - third = createOrProof(in2, out1, in2, out2, r2, false); - fourth = createOrProof(in1, out2, in2, out2, r2, false); + first = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), + organizer.getE2(ProofOrganizer.OrProofOrder.first), + organizer.getE1New(ProofOrganizer.OrProofOrder.first), + organizer.getE2New(ProofOrganizer.OrProofOrder.first), + r1, true); + second = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), + organizer.getE2(ProofOrganizer.OrProofOrder.second), + organizer.getE1New(ProofOrganizer.OrProofOrder.second), + organizer.getE2New(ProofOrganizer.OrProofOrder.second), r1, true); + third = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), + organizer.getE2(ProofOrganizer.OrProofOrder.third), + organizer.getE1New(ProofOrganizer.OrProofOrder.third), + organizer.getE2New(ProofOrganizer.OrProofOrder.third), r2, false); + fourth = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2(ProofOrganizer.OrProofOrder.fourth), + organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), r2, false); } else { - first = createOrProof(in1, out1, in2, out1, r2, false); - second = createOrProof(in1, out1, in1, out2, r1, false); - third = createOrProof(in2, out1, in2, out2, r2, true); - fourth = createOrProof(in1, out2, in2, out2, r1, true); + first = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), + organizer.getE2(ProofOrganizer.OrProofOrder.first), + organizer.getE1New(ProofOrganizer.OrProofOrder.first), + organizer.getE2New(ProofOrganizer.OrProofOrder.first), + r2, false); + second = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), + organizer.getE2(ProofOrganizer.OrProofOrder.second), + organizer.getE1New(ProofOrganizer.OrProofOrder.second), + organizer.getE2New(ProofOrganizer.OrProofOrder.second), + r1, false); + third = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), + organizer.getE2(ProofOrganizer.OrProofOrder.third), + organizer.getE1New(ProofOrganizer.OrProofOrder.third), + organizer.getE2New(ProofOrganizer.OrProofOrder.third), + r2, true); + fourth = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2(ProofOrganizer.OrProofOrder.fourth), + organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), + r1, true); } Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() .setI(i) .setJ(j) .setLayer(layer) .build(); - return Mixing.ZeroKnowledgeProof.newBuilder() + + + + Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() .setFirst(first) .setSecond(second) .setThird(third) .setFourth(fourth) .setLocation(location) .build(); + + //debuging + if (verifier != null){ + if (!verifier.verify(in1,in2,out1,out2,result)){ + + System.out.print(location.toString()); + System.out.println("switch value : " + sw); + } + } + + return result; } private Mixing.ZeroKnowledgeProof.OrProof createOrProof(Crypto.RerandomizableEncryptedMessage e1, @@ -68,42 +137,51 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage e1New, Crypto.RerandomizableEncryptedMessage e2New, Crypto.EncryptionRandomness x, - boolean flag){ - - ElGamalCiphertext e1ElGamal = general.calcRerandomizable2ElGamal(e1); - ElGamalCiphertext e2ElGamal = general.calcRerandomizable2ElGamal(e2); - ElGamalCiphertext e1TagElGamal = general.calcRerandomizable2ElGamal(e1New); - ElGamalCiphertext e2TagElGamal = general.calcRerandomizable2ElGamal(e2New); + boolean flag) throws InvalidProtocolBufferException { + ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); + ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,x,flag); } - + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { + byte[] arr = input.toByteArray(); + return new BigInteger(this.randomOracle.hash(arr,arr.length)); + } + + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalCiphertext e1, ElGamalCiphertext e2, ElGamalCiphertext e1New, ElGamalCiphertext e2New, Crypto.EncryptionRandomness x, boolean flag) { - ByteString g1 = general.getG(); - ByteString h1 = group.add(e1New.getC1(),group.negate(e1.getC1())); - ByteString g2 = general.getH(); - ByteString h2 = group.add(e1New.getC2(),group.negate(e1.getC2())); - ByteString g1Tag = general.getG(); - ByteString h1Tag = group.add(e2New.getC1(),group.negate(e2.getC1())); - ByteString g2Tag = general.getH(); - ByteString h2Tag = group.add(e2New.getC2(),group.negate(e2.getC2())); + ECPoint g1 = g; + ECPoint h1 = group.add(convert2ECPoint(e1New.getC1()),group.negate(convert2ECPoint(e1.getC1()))); + ECPoint g2 = h; + ECPoint h2 = group.add(convert2ECPoint(e1New.getC2()),group.negate(convert2ECPoint(e1.getC2()))); - BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + ECPoint g1Tag = g; + ECPoint h1Tag = group.add(convert2ECPoint(e2New.getC1()),group.negate(convert2ECPoint(e2.getC1()))); + ECPoint g2Tag = h; + ECPoint h2Tag = group.add(convert2ECPoint(e2New.getC2()),group.negate(convert2ECPoint(e2.getC2()))); + + BigInteger r = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); BigInteger c1,c2,z,zTag; - ByteString u,v,uTag,vTag; + ECPoint u,v,uTag,vTag; if (flag) { - c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + c2 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + zTag = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); //step 1 u = group.multiply(g1, r); v = group.multiply(g2, r); @@ -113,28 +191,28 @@ public class Prover implements Mix2ZeroKnowledgeProver { // c1 = (hash(input + step1) + group size - c2)% group size Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(g1) - .setH1(h1) - .setG2(g2) - .setH2(h2) - .setG1Tag(g1Tag) - .setH1Tag(h1Tag) - .setG2Tag(g2Tag) - .setH2Tag(h2Tag) - .setU(u) - .setV(v) - .setUTag(uTag) - .setVTag(vTag) + .setG1(ByteString.copyFrom(group.encode(g1))) + .setH1(ByteString.copyFrom(group.encode(h1))) + .setG2(ByteString.copyFrom(group.encode(g2))) + .setH2(ByteString.copyFrom(group.encode(h2))) + .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) + .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) + .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) + .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) .build(); - c1 = general.hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); + c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); //step 3 //z = (r + c1 * x) % group size; z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); } else { - c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + c1 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + z = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); //step 1 uTag = group.multiply(g1Tag, r); vTag = group.multiply(g2Tag, r); @@ -144,37 +222,37 @@ public class Prover implements Mix2ZeroKnowledgeProver { // c1 = (hash(input + step1) + group size - c1)% group size Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(g1) - .setH1(h1) - .setG2(g2) - .setH2(h2) - .setG1Tag(g1Tag) - .setH1Tag(h1Tag) - .setG2Tag(g2Tag) - .setH2Tag(h2Tag) - .setU(u) - .setV(v) - .setUTag(uTag) - .setVTag(vTag) + .setG1(ByteString.copyFrom(group.encode(g1))) + .setH1(ByteString.copyFrom(group.encode(h1))) + .setG2(ByteString.copyFrom(group.encode(g2))) + .setH2(ByteString.copyFrom(group.encode(h2))) + .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) + .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) + .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) + .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) .build(); - c2 = general.hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); + c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); //step 3 //zTag = (r + c2 * x) % group size; zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); } return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() - .setG1(g1) - .setH1(h1) - .setG2(g2) - .setH2(h2) - .setG1Tag(g1Tag) - .setH1Tag(h1Tag) - .setG2Tag(g2Tag) - .setH2Tag(h2Tag) - .setU(u) - .setV(v) - .setUTag(uTag) - .setVTag(vTag) + .setG1(ByteString.copyFrom(group.encode(g1))) + .setH1(ByteString.copyFrom(group.encode(h1))) + .setG2(ByteString.copyFrom(group.encode(g2))) + .setH2(ByteString.copyFrom(group.encode(h2))) + .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) + .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) + .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) + .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) .setC1(ByteString.copyFrom(c1.toByteArray())) .setC2(ByteString.copyFrom(c2.toByteArray())) .setZ(ByteString.copyFrom(z.toByteArray())) diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index d70bd91..19549ce 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -1,17 +1,24 @@ package verifier; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import necessary.General; -import qilin.primitives.Group; +import org.bouncycastle.math.ec.ECPoint; +import prover.ProofOrganizer; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; +import java.util.List; public class Verifier implements Mix2ZeroKnowledgeVerifier { + /** * Return true iff the proof is valid. * @param in1 @@ -21,38 +28,78 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { * @return */ - Group group; - General general; + ECGroup group; + RandomOracle randomOracle; + ECElGamalEncryption encryptor; + ECPoint g,h; - public Verifier(Group group,General general) { - this.group = group; - this.general = general; + public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { + this.encryptor = encryptor; + this.group = encryptor.getGroup(); + this.g = group.getGenerator(); + this.h = encryptor.getElGamalPK().getPK(); + this.randomOracle = randomOracle; } + public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { + byte[] arr = input.toByteArray(); + return new BigInteger(this.randomOracle.hash(arr,arr.length)); + } + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + public boolean verify(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof) - { + Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { - ElGamalCiphertext e1ElGamal = general.calcRerandomizable2ElGamal(in1); - ElGamalCiphertext e2ElGamal = general.calcRerandomizable2ElGamal(in2); - ElGamalCiphertext e1TagElGamal = general.calcRerandomizable2ElGamal(out1); - ElGamalCiphertext e2TagElGamal = general.calcRerandomizable2ElGamal(out2); + ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2); + return verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), + organizer.getE2(ProofOrganizer.OrProofOrder.first), + organizer.getE1New(ProofOrganizer.OrProofOrder.first), + organizer.getE2New(ProofOrganizer.OrProofOrder.first), + proof.getFirst(),ProofOrganizer.OrProofOrder.first)&& + verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), + organizer.getE2(ProofOrganizer.OrProofOrder.second), + organizer.getE1New(ProofOrganizer.OrProofOrder.second), + organizer.getE2New(ProofOrganizer.OrProofOrder.second), + proof.getSecond(),ProofOrganizer.OrProofOrder.second)&& + verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), + organizer.getE2(ProofOrganizer.OrProofOrder.third), + organizer.getE1New(ProofOrganizer.OrProofOrder.third), + organizer.getE2New(ProofOrganizer.OrProofOrder.third), + proof.getThird(),ProofOrganizer.OrProofOrder.third)&& + verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2(ProofOrganizer.OrProofOrder.fourth), + organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), + organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), + proof.getFourth(),ProofOrganizer.OrProofOrder.fourth); + } - return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getFirst()) && - verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getSecond()) && - verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getThird()) && - verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,proof.getFourth()); + + public boolean verifyOrProof(Crypto.RerandomizableEncryptedMessage e1, + Crypto.RerandomizableEncryptedMessage e2, + Crypto.RerandomizableEncryptedMessage e1Tag, + Crypto.RerandomizableEncryptedMessage e2Tag, + Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) throws InvalidProtocolBufferException { + + ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1Tag); + ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2Tag); + return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProof,orProofOrder); } public boolean verifyElGamaOrProof(ElGamalCiphertext e1, ElGamalCiphertext e2, ElGamalCiphertext e1New, ElGamalCiphertext e2New, - Mixing.ZeroKnowledgeProof.OrProof orProof) + Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) { Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = @@ -71,30 +118,107 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { .setVTag(orProof.getVTag()) .build(); + ECPoint g1,g2,h1,h2; + ECPoint g1Tag,g2Tag,h1Tag,h2Tag; + g1 = convert2ECPoint(orProof.getG1()); + g2 = convert2ECPoint(orProof.getG2()); + h1 = convert2ECPoint(orProof.getH1()); + h2 = convert2ECPoint(orProof.getH2()); + g1Tag = convert2ECPoint(orProof.getG1Tag()); + g2Tag = convert2ECPoint(orProof.getG2Tag()); + h1Tag = convert2ECPoint(orProof.getH1Tag()); + h2Tag = convert2ECPoint(orProof.getH2Tag()); + + ECPoint u,v,uTag,vTag; + u = convert2ECPoint(orProof.getU()); + v = convert2ECPoint(orProof.getV()); + uTag = convert2ECPoint(orProof.getUTag()); + vTag = convert2ECPoint(orProof.getVTag()); + + BigInteger c1,c2,z,zTag; + c1 = new BigInteger(orProof.getC1().toByteArray()); + c2 = new BigInteger(orProof.getC2().toByteArray()); + z = new BigInteger(orProof.getZ().toByteArray()); + zTag = new BigInteger(orProof.getZTag().toByteArray()); + + ECPoint[] given = new ECPoint[12]; + ECPoint[] expected = new ECPoint[12]; + String[] description = new String[12]; + int i = 0; + given[i++] = g1; + given[i++] = h1; + given[i++] = g2; + given[i++] = h2; + given[i++] = g1Tag; + given[i++] = h1Tag; + given[i++] = g2Tag; + given[i++] = h2Tag; + given[i++] = group.multiply(g1, z); + given[i++] = group.multiply(g2, z); + given[i++] = group.multiply(g1Tag, zTag); + given[i] = group.multiply(g2Tag, zTag); + i = 0; + expected[i++] = g; + expected[i++] = group.add(convert2ECPoint(e1New.getC1()), group.negate(convert2ECPoint(e1.getC1()))); + expected[i++] = h; + expected[i++] = group.add(convert2ECPoint(e1New.getC2()), group.negate(convert2ECPoint(e1.getC2()))); + expected[i++] = g; + expected[i++] = group.add(convert2ECPoint(e2New.getC1()), group.negate(convert2ECPoint(e2.getC1()))); + expected[i++] = h; + expected[i++] = group.add(convert2ECPoint(e2New.getC2()), group.negate(convert2ECPoint(e2.getC2()))); + expected[i++] = group.add(u, group.multiply(h1,c1)); + expected[i++] = group.add(v, group.multiply(h2,c1)); + expected[i++] = group.add(uTag, group.multiply(h1Tag,c2)); + expected[i] = group.add(vTag, group.multiply(h2Tag,c2)); + i = 0; + description[i++] = "g1 != g"; + description[i++] = "h1 != e1New.c1/e1.c1"; + description[i++] = "g2 != h"; + description[i++] = "h2 != e1New.c2/e1.c2"; + description[i++] = "g1Tag != g"; + description[i++] = "h1Tag != e2New.c1/e2.c1"; + description[i++] = "g2Tag != h"; + description[i++] = "h2Tag != e2New.c2/e2.c2"; + description[i++] = "g1 ^ z != u * ( h1 ^ c1 )"; + description[i++] = "g2 ^ z != v * ( h2 ^ c1 )"; + description[i++] = "g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )"; + description[i] = "g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )"; + boolean first = true; + for (int j = 0; j < given.length ; j++){ + if(!given[j].equals(expected[j])){ + if (first){ + first = false; + System.out.print("\n\n\n"); + System.out.println(orProofOrder.toString()); + } + System.out.println(description[j]); + } + } + return //input - orProof.getG1().equals(general.getG())&& - orProof.getH1().equals(group.add(e1New.getC1(), group.negate(e1.getC1())))&& - orProof.getG2().equals(general.getH())&& - orProof.getH2().equals(group.add(e1New.getC2(), group.negate(e1.getC2())))&& + g1.equals(g)&& + h1.equals(group.add(convert2ECPoint(e1New.getC1()) + , group.negate(convert2ECPoint(e1.getC1()))))&& + g2.equals(h)&& + h2.equals(group.add(convert2ECPoint(e1New.getC2()) + , group.negate(convert2ECPoint(e1.getC2()))))&& // input' - orProof.getG1Tag().equals(general.getG())&& - orProof.getH1Tag().equals(group.add(e2New.getC1(), group.negate(e2.getC1())))&& - orProof.getG2Tag().equals(general.getH())&& - orProof.getH2Tag().equals(group.add(e2New.getC2(), group.negate(e2.getC2()))) && + g1Tag.equals(g)&& + h1Tag.equals(group.add(convert2ECPoint(e2New.getC1()) + , group.negate(convert2ECPoint(e2.getC1()))))&& + g2Tag.equals(h)&& + h2Tag.equals(group.add(convert2ECPoint(e2New.getC2()) + , group.negate(convert2ECPoint(e2.getC2())))) && // hash // assert (c1 + c2 ) % group size == hash (imput + step1) % group size new BigInteger(orProof.getC1().toByteArray()).add(new BigInteger(orProof.getC2().toByteArray())).mod(group.orderUpperBound()) - .equals(general.hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()))&& + .equals(hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()))&& // proof // g1 ^ z == u * ( h1 ^ c1 ) && g2 ^ z == v * ( h2 ^ c1 ) && the same for tag case - group.multiply(orProof.getG1(), new BigInteger(orProof.getZ().toByteArray())) - .equals(group.add(orProof.getU(), group.multiply(orProof.getH1(),new BigInteger(orProof.getC1().toByteArray())))) && - group.multiply(orProof.getG2(), new BigInteger(orProof.getZ().toByteArray())) - .equals(group.add(orProof.getV(), group.multiply(orProof.getH2(),new BigInteger(orProof.getC1().toByteArray())))) && - group.multiply(orProof.getG1Tag(), new BigInteger(orProof.getZTag().toByteArray())) - .equals(group.add(orProof.getUTag(), group.multiply(orProof.getH1Tag(),new BigInteger(orProof.getC2().toByteArray())))) && - group.multiply(orProof.getG2Tag(), new BigInteger(orProof.getZTag().toByteArray())) - .equals(group.add(orProof.getVTag(), group.multiply(orProof.getH2Tag(),new BigInteger(orProof.getC2().toByteArray())))); + group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1))) && + group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1))) && + group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2))) && + group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2))); } } diff --git a/mixer/src/main/java/verifier/VerifyTable.java b/mixer/src/main/java/verifier/VerifyTable.java new file mode 100644 index 0000000..a0075c0 --- /dev/null +++ b/mixer/src/main/java/verifier/VerifyTable.java @@ -0,0 +1,83 @@ +package verifier; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import qilin.util.Pair; + +import java.util.Arrays; + +/** + * Created by Tzlil on 12/30/2015. + */ +public final class VerifyTable { + + public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,Pair mixerOutput) throws InvalidProtocolBufferException { + int index1,index2,layer; + + //assert n = 2^k + if ( (n &(n-1)) != 0) + throw new IllegalArgumentException("n"); + + int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1; + //initialize locationChecksum table + // use for check BeneshNet validity + boolean[][] locationChecksum = new boolean[layers][n]; + for (boolean[] locationChecksumLayer: locationChecksum) { + Arrays.fill(locationChecksumLayer,false); + } + + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.a; + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.b; + + for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { + for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { + Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + index1 = location.getI(); + index2 = location.getJ(); + layer = location.getLayer(); + + // check location validity + if (layer > layers >> 1) { + if (index2 - index1 != n >> (layers - layer)) + return false; + } + else{ + if (index2 - index1 != n >> (layer + 1)) + return false; + } + + // mark location in table + locationChecksum[layer][index1] = true; + locationChecksum[layer][index2] = true; + + // verify proof + if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp)) { + + verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp); + System.out.print("\n\n\nlayer " + layer + " i , j " + index1 + " , " + index2 + "\n\n\n"); + return false; + } + } + } + + // verify all necessary locations for BeneshNet were proved + for (boolean[] checksumLayer: locationChecksum) { + for (boolean locationBoolean: checksumLayer) { + if (!locationBoolean) + return false; + } + } + return true; + } +} diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java new file mode 100644 index 0000000..5081850 --- /dev/null +++ b/mixer/src/test/java/mixer/MixingText.java @@ -0,0 +1,113 @@ +package mixer; + +/** + * Created by Tzlil on 12/30/2015. + */ +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.concrete.GlobalCryptoSetup; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import qilin.primitives.generic.ElGamal; +import qilin.util.Pair; +import verifier.Verifier; +import verifier.VerifyTable; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class MixingText { + + ECElGamalEncryption encryptor; + ECGroup group; + Random random ; + private BigInteger sk; + private ECElGamal.SK key; + private ConcreteCrypto.ElGamalPublicKey serializedPk; + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (Exception e) { + throw new RuntimeException("Error converting public key!", e); + } + } + + @Test + public void mixingTest() throws InvalidProtocolBufferException, InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + sk = ECElGamal.generateSecretKey(group, random); + key = new ECElGamal.SK(group, sk); + serializedPk = serializePk(group, key); + encryptor = new ECElGamalEncryption(); + encryptor.init(serializedPk); + + + Random randomMixer = new Random(); + Random randomProver = new Random(); + RandomOracle randomOracle = new DigestOracle(); + + Mix2ZeroKnowledgeVerifier verifier = new Verifier(encryptor,randomOracle); + Mix2ZeroKnowledgeProver prover = new Prover(randomProver,encryptor,randomOracle,verifier); + meerkat.crypto.mixnet.Mixer mixer = new Mixer(randomMixer,prover,encryptor); + ECGroup group = encryptor.getGroup(); + + + // generate n + int logN = 7; // + random.nextInt(8) + int layers = 2*logN - 1; + int n = 1 << logN; + + // generate MixerInput + List mixerInput = new ArrayList(); + Message message; + for (int i = 0; i < n ; i++){ + message = Mixing.Plaintext.newBuilder() + .setData(ByteString.copyFrom(group.encode(group.sample(random)))) + .build(); + mixerInput.add(encryptor.encrypt(message, encryptor.generateRandomness(random))); + } + + Pair mixerOutput = mixer.mix(mixerInput); + +// assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); + } +} From 8f75bebaea0d855757e8d42cc0c269ff0539be9c Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 1 Jan 2016 00:39:17 +0200 Subject: [PATCH 11/66] testing in progress --- mixer/src/test/java/mixer/MixingText.java | 1 - .../java/mixer/ZeroKnowledgeProofTest.java | 171 ++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index 5081850..c5f8f33 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -69,7 +69,6 @@ public class MixingText { } } - @Test public void mixingTest() throws InvalidProtocolBufferException, InvalidKeySpecException { // initialization random = new Random(); diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java new file mode 100644 index 0000000..e75ce19 --- /dev/null +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -0,0 +1,171 @@ +package mixer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.concrete.GlobalCryptoSetup; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import meerkat.protobuf.Voting; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import qilin.primitives.generic.ElGamal; +import qilin.util.Pair; +import verifier.Verifier; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Random; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Tzlil on 12/31/2015. + */ +public class ZeroKnowledgeProofTest { + + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (Exception e) { + throw new RuntimeException("Error converting public key!", e); + } + } + + /** + * Standard (non-threshold) decryption for testing purposes. + * @param secretKey + * @return + */ + public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) + throws InvalidProtocolBufferException { + ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); + ByteString c1encoded = cipherText.getC1(); + ByteString c2encoded = cipherText.getC2(); + + ECPoint c1 = group.decode(c1encoded.toByteArray()); + ECPoint c2 = group.decode(c2encoded.toByteArray()); + + assert (group.contains(c1)); + assert (group.contains(c2)); + + ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); + + byte[] plaintext = group.injectiveDecode(plaintextEncoded); + + ByteArrayInputStream in = new ByteArrayInputStream(plaintext); + + try { + java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); + builder.mergeDelimitedFrom(in); + return plaintextMessageType.cast(builder.build()); + } catch (Exception e) { + throw new InvalidProtocolBufferException("Plaintext protobuf error"); + } + } + + + Random rand = new Random(0); // Insecure deterministic random for testing. + + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + Mix2ZeroKnowledgeVerifier verifier ; + Mix2ZeroKnowledgeProver prover ; + + @Before + public void setup() throws Exception { + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = serializePk(group, key); + + + enc = new ECElGamalEncryption(); + + enc.init(serializedPk); + RandomOracle randomOracle = new DigestOracle(); + verifier = new Verifier(enc,randomOracle); + prover = new Prover(new Random(),enc,randomOracle); + } + + + Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { + Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); + ballot.setSerialNumber(rand.nextInt(1000000)); + for (int i = 0; i < numQuestions; ++i) { + Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); + for (int j = 0; j < numAnswers; ++j) { + answers.addAnswer(rand.nextInt(maxAnswer)); + } + } + return ballot.build(); + } + + + public void oneZKPTest() throws InvalidProtocolBufferException { + + Voting.PlaintextBallot msg1 = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Voting.PlaintextBallot msg2 = genRandomBallot(2,3,16); + Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand); + Crypto.EncryptionRandomness r2 = enc.generateRandomness(rand); + + Crypto.RerandomizableEncryptedMessage e1 = enc.encrypt(msg1, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage e2 = enc.encrypt(msg2, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage e1Tag = enc.rerandomize(e1, r1); + Crypto.RerandomizableEncryptedMessage e2Tag = enc.rerandomize(e2, r2); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e1Tag).equals(msg1)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e2Tag).equals(msg2)); + assert (verifier.verify(e1,e2,e1Tag,e2Tag,prover.prove(e1,e2,e1Tag,e2Tag,false,0,0,0,r1,r2))); + } + + @Test + public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException { + + int tests = 1000; + + for (int i = 0; i < tests; i ++){ + System.out.println("test " + i); + oneZKPTest(); + } + } +} From 8a07f86c0fc16e840e8ba9b07ee818f730496deb Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 1 Jan 2016 11:37:54 +0200 Subject: [PATCH 12/66] more tests for mixer --- mixer/src/main/java/verifier/Verifier.java | 158 ++++++++---------- mixer/src/test/java/mixer/MixNetworkTest.java | 2 - mixer/src/test/java/mixer/MixingText.java | 103 ++++-------- mixer/src/test/java/mixer/Utiles.java | 102 +++++++++++ .../java/mixer/ZeroKnowledgeProofTest.java | 111 ++---------- 5 files changed, 218 insertions(+), 258 deletions(-) create mode 100644 mixer/src/test/java/mixer/Utiles.java diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index 19549ce..c8c9914 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -13,6 +13,7 @@ import qilin.primitives.RandomOracle; import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; +import java.util.ArrayList; import java.util.List; @@ -95,14 +96,16 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProof,orProofOrder); } - public boolean verifyElGamaOrProof(ElGamalCiphertext e1, - ElGamalCiphertext e2, - ElGamalCiphertext e1New, - ElGamalCiphertext e2New, - Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) - { - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = + + private ECPoint g1,g2,h1,h2; + private ECPoint g1Tag,g2Tag,h1Tag,h2Tag; + private ECPoint u,v,uTag,vTag; + private BigInteger c1,c2,z,zTag; + private Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + private void parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ + forRandomOracle = Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() .setG1(orProof.getG1()) .setH1(orProof.getH1()) @@ -117,9 +120,6 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { .setUTag(orProof.getUTag()) .setVTag(orProof.getVTag()) .build(); - - ECPoint g1,g2,h1,h2; - ECPoint g1Tag,g2Tag,h1Tag,h2Tag; g1 = convert2ECPoint(orProof.getG1()); g2 = convert2ECPoint(orProof.getG2()); h1 = convert2ECPoint(orProof.getH1()); @@ -128,97 +128,83 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { g2Tag = convert2ECPoint(orProof.getG2Tag()); h1Tag = convert2ECPoint(orProof.getH1Tag()); h2Tag = convert2ECPoint(orProof.getH2Tag()); - - ECPoint u,v,uTag,vTag; u = convert2ECPoint(orProof.getU()); v = convert2ECPoint(orProof.getV()); uTag = convert2ECPoint(orProof.getUTag()); vTag = convert2ECPoint(orProof.getVTag()); - - BigInteger c1,c2,z,zTag; c1 = new BigInteger(orProof.getC1().toByteArray()); c2 = new BigInteger(orProof.getC2().toByteArray()); z = new BigInteger(orProof.getZ().toByteArray()); zTag = new BigInteger(orProof.getZTag().toByteArray()); + } - ECPoint[] given = new ECPoint[12]; - ECPoint[] expected = new ECPoint[12]; - String[] description = new String[12]; - int i = 0; - given[i++] = g1; - given[i++] = h1; - given[i++] = g2; - given[i++] = h2; - given[i++] = g1Tag; - given[i++] = h1Tag; - given[i++] = g2Tag; - given[i++] = h2Tag; - given[i++] = group.multiply(g1, z); - given[i++] = group.multiply(g2, z); - given[i++] = group.multiply(g1Tag, zTag); - given[i] = group.multiply(g2Tag, zTag); - i = 0; - expected[i++] = g; - expected[i++] = group.add(convert2ECPoint(e1New.getC1()), group.negate(convert2ECPoint(e1.getC1()))); - expected[i++] = h; - expected[i++] = group.add(convert2ECPoint(e1New.getC2()), group.negate(convert2ECPoint(e1.getC2()))); - expected[i++] = g; - expected[i++] = group.add(convert2ECPoint(e2New.getC1()), group.negate(convert2ECPoint(e2.getC1()))); - expected[i++] = h; - expected[i++] = group.add(convert2ECPoint(e2New.getC2()), group.negate(convert2ECPoint(e2.getC2()))); - expected[i++] = group.add(u, group.multiply(h1,c1)); - expected[i++] = group.add(v, group.multiply(h2,c1)); - expected[i++] = group.add(uTag, group.multiply(h1Tag,c2)); - expected[i] = group.add(vTag, group.multiply(h2Tag,c2)); - i = 0; - description[i++] = "g1 != g"; - description[i++] = "h1 != e1New.c1/e1.c1"; - description[i++] = "g2 != h"; - description[i++] = "h2 != e1New.c2/e1.c2"; - description[i++] = "g1Tag != g"; - description[i++] = "h1Tag != e2New.c1/e2.c1"; - description[i++] = "g2Tag != h"; - description[i++] = "h2Tag != e2New.c2/e2.c2"; - description[i++] = "g1 ^ z != u * ( h1 ^ c1 )"; - description[i++] = "g2 ^ z != v * ( h2 ^ c1 )"; - description[i++] = "g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )"; - description[i] = "g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )"; - boolean first = true; - for (int j = 0; j < given.length ; j++){ - if(!given[j].equals(expected[j])){ - if (first){ - first = false; + private List createConditionsList(ElGamalCiphertext e1, + ElGamalCiphertext e2, + ElGamalCiphertext e1New, + ElGamalCiphertext e2New){ + List conditions = new ArrayList(); + conditions.add(new Condition( g1,g,"g1 != g")); + conditions.add(new Condition( h1,group.add(convert2ECPoint(e1New.getC1()), + group.negate(convert2ECPoint(e1.getC1()))),"h1 != e1New.c1/e1.c1")); + conditions.add(new Condition( g2,h,"g2 != h")); + conditions.add(new Condition( h2,group.add(convert2ECPoint(e1New.getC2()), + group.negate(convert2ECPoint(e1.getC2()))),"h2 != e1New.c2/e1.c2")); + conditions.add(new Condition( g1Tag,g,"g1Tag != g")); + conditions.add(new Condition( h1Tag,group.add(convert2ECPoint(e2New.getC1()), + group.negate(convert2ECPoint(e2.getC1()))),"h1Tag != e2New.c1/e2.c1")); + conditions.add(new Condition( g2Tag,h,"g2Tag != h")); + conditions.add(new Condition( h2Tag,group.add(convert2ECPoint(e2New.getC2()), + group.negate(convert2ECPoint(e2.getC2()))),"h2Tag != e2New.c2/e2.c2")); + conditions.add(new Condition(c1.add(c2).mod(group.orderUpperBound()), + hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()), + "(c1 + c2 ) % group size == hash (imput + step1) % group size")); + conditions.add(new Condition( group.multiply(g1, z), + group.add(u, group.multiply(h1,c1)),"g1 ^ z != u * ( h1 ^ c1 )")); + conditions.add(new Condition( group.multiply(g2, z), + group.add(v, group.multiply(h2,c1)),"g2 ^ z != v * ( h2 ^ c1 )")); + conditions.add(new Condition( group.multiply(g1Tag, zTag), + group.add(uTag, group.multiply(h1Tag,c2)),"g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )")); + conditions.add(new Condition( group.multiply(g2Tag, zTag), + group.add(vTag, group.multiply(h2Tag,c2)),"g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )")); + return conditions; + } + + public boolean verifyElGamaOrProof(ElGamalCiphertext e1, + ElGamalCiphertext e2, + ElGamalCiphertext e1New, + ElGamalCiphertext e2New, + Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) + { + parseOrProof(orProof); + List conditions = createConditionsList(e1,e2,e1New,e2New); + + boolean result = true; + for (Condition condition: conditions) { + if(!condition.test()){ + if (result){ + result = false; System.out.print("\n\n\n"); System.out.println(orProofOrder.toString()); } - System.out.println(description[j]); + System.out.println(condition.errorDescripton); } } + return result; + } - return //input - g1.equals(g)&& - h1.equals(group.add(convert2ECPoint(e1New.getC1()) - , group.negate(convert2ECPoint(e1.getC1()))))&& - g2.equals(h)&& - h2.equals(group.add(convert2ECPoint(e1New.getC2()) - , group.negate(convert2ECPoint(e1.getC2()))))&& - // input' - g1Tag.equals(g)&& - h1Tag.equals(group.add(convert2ECPoint(e2New.getC1()) - , group.negate(convert2ECPoint(e2.getC1()))))&& - g2Tag.equals(h)&& - h2Tag.equals(group.add(convert2ECPoint(e2New.getC2()) - , group.negate(convert2ECPoint(e2.getC2())))) && - // hash - // assert (c1 + c2 ) % group size == hash (imput + step1) % group size - new BigInteger(orProof.getC1().toByteArray()).add(new BigInteger(orProof.getC2().toByteArray())).mod(group.orderUpperBound()) - .equals(hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()))&& - // proof - // g1 ^ z == u * ( h1 ^ c1 ) && g2 ^ z == v * ( h2 ^ c1 ) && the same for tag case - group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1))) && - group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1))) && - group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2))) && - group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2))); + private class Condition{ + T given, expected; + String errorDescripton; + + Condition(T given,T expected,String descripton){ + this.given = given; + this.errorDescripton = descripton; + this.expected = expected; + } + + boolean test(){ + return given.equals(expected); + } } } diff --git a/mixer/src/test/java/mixer/MixNetworkTest.java b/mixer/src/test/java/mixer/MixNetworkTest.java index 4652460..d5faed5 100644 --- a/mixer/src/test/java/mixer/MixNetworkTest.java +++ b/mixer/src/test/java/mixer/MixNetworkTest.java @@ -5,7 +5,6 @@ package mixer; */ import org.junit.Test; - import java.util.Arrays; import java.util.Random; @@ -16,7 +15,6 @@ public class MixNetworkTest { Random random = new Random(); int logn = 10; - int n = 1 << logn; int layers = 2*logn - 1; RandomPermutation randomPermutation = new RandomPermutation(n,random); diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index c5f8f33..a4b9c81 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -3,33 +3,24 @@ package mixer; /** * Created by Tzlil on 12/30/2015. */ -import com.google.protobuf.ByteString; + import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.concrete.GlobalCryptoSetup; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECPoint; +import meerkat.protobuf.Voting; +import org.junit.Before; import org.junit.Test; import prover.Prover; import qilin.primitives.RandomOracle; import qilin.primitives.concrete.DigestOracle; import qilin.primitives.concrete.ECElGamal; import qilin.primitives.concrete.ECGroup; -import qilin.primitives.generic.ElGamal; import qilin.util.Pair; import verifier.Verifier; import verifier.VerifyTable; - -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.List; @@ -39,74 +30,48 @@ public class MixingText { ECElGamalEncryption encryptor; ECGroup group; - Random random ; - private BigInteger sk; - private ECElGamal.SK key; - private ConcreteCrypto.ElGamalPublicKey serializedPk; + Random random,randomMixer,randomProver; + RandomOracle randomOracle; + Mix2ZeroKnowledgeVerifier verifier; + Mix2ZeroKnowledgeProver prover; + meerkat.crypto.mixnet.Mixer mixer; + private int layers; + private int n; - public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; - /** - * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} - * @param pk - * @return - */ - public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { - ECPoint pkPoint = pk.getPK(); - ECParameterSpec params = group.getCurveParams(); - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); - - try { - KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); - PublicKey javaPk = fact.generatePublic(pubKeySpec); - ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() - .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); - - return serializedPk; - } catch (Exception e) { - throw new RuntimeException("Error converting public key!", e); - } - } - - public void mixingTest() throws InvalidProtocolBufferException, InvalidKeySpecException { + @Before + public void setup() throws InvalidKeySpecException { // initialization random = new Random(); group = new ECGroup("secp256k1"); - sk = ECElGamal.generateSecretKey(group, random); - key = new ECElGamal.SK(group, sk); - serializedPk = serializePk(group, key); encryptor = new ECElGamalEncryption(); - encryptor.init(serializedPk); - - - Random randomMixer = new Random(); - Random randomProver = new Random(); - RandomOracle randomOracle = new DigestOracle(); - - Mix2ZeroKnowledgeVerifier verifier = new Verifier(encryptor,randomOracle); - Mix2ZeroKnowledgeProver prover = new Prover(randomProver,encryptor,randomOracle,verifier); - meerkat.crypto.mixnet.Mixer mixer = new Mixer(randomMixer,prover,encryptor); - ECGroup group = encryptor.getGroup(); - + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + randomMixer = new Random(); + randomProver = new Random(); + randomOracle = new DigestOracle(); + verifier = new Verifier(encryptor,randomOracle); + prover = new Prover(randomProver,encryptor,randomOracle,verifier); + mixer = new Mixer(randomMixer,prover,encryptor); // generate n - int logN = 7; // + random.nextInt(8) - int layers = 2*logN - 1; - int n = 1 << logN; + int logN = 8; // + random.nextInt(8) + layers = 2*logN - 1; + n = 1 << logN; + } - // generate MixerInput - List mixerInput = new ArrayList(); - Message message; + public List generateMixerInput(){ + List result = new ArrayList(); + Voting.PlaintextBallot msg; for (int i = 0; i < n ; i++){ - message = Mixing.Plaintext.newBuilder() - .setData(ByteString.copyFrom(group.encode(group.sample(random)))) - .build(); - mixerInput.add(encryptor.encrypt(message, encryptor.generateRandomness(random))); + msg = Utiles.genRandomBallot(2,3,16); + result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); } + return result; + } - Pair mixerOutput = mixer.mix(mixerInput); - -// assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); + @Test + public void mixingTest() throws InvalidProtocolBufferException { + Pair mixerOutput = mixer.mix(generateMixerInput()); + assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); } } diff --git a/mixer/src/test/java/mixer/Utiles.java b/mixer/src/test/java/mixer/Utiles.java new file mode 100644 index 0000000..2be2a1c --- /dev/null +++ b/mixer/src/test/java/mixer/Utiles.java @@ -0,0 +1,102 @@ +package mixer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.concrete.GlobalCryptoSetup; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import qilin.primitives.generic.ElGamal; +import qilin.util.Pair; + +import java.io.ByteArrayInputStream; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.util.Random; + +/** + * Created by Tzlil on 1/1/2016. + */ +public class Utiles { + + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (Exception e) { + throw new RuntimeException("Error converting public key!", e); + } + } + + /** + * Standard (non-threshold) decryption for testing purposes. + * @param secretKey + * @return + */ + public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) + throws InvalidProtocolBufferException { + ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); + ByteString c1encoded = cipherText.getC1(); + ByteString c2encoded = cipherText.getC2(); + + ECPoint c1 = group.decode(c1encoded.toByteArray()); + ECPoint c2 = group.decode(c2encoded.toByteArray()); + + assert (group.contains(c1)); + assert (group.contains(c2)); + + ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); + + byte[] plaintext = group.injectiveDecode(plaintextEncoded); + + ByteArrayInputStream in = new ByteArrayInputStream(plaintext); + + try { + java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); + builder.mergeDelimitedFrom(in); + return plaintextMessageType.cast(builder.build()); + } catch (Exception e) { + throw new InvalidProtocolBufferException("Plaintext protobuf error"); + } + } + + static Random random = new Random(); + + public static Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { + Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); + ballot.setSerialNumber(random.nextInt(1000000)); + for (int i = 0; i < numQuestions; ++i) { + Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); + for (int j = 0; j < numAnswers; ++j) { + answers.addAnswer(random.nextInt(maxAnswer)); + } + } + return ballot.build(); + } +} diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index e75ce19..9c50f74 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -1,20 +1,12 @@ package mixer; -import com.google.protobuf.ByteString; -import com.google.protobuf.GeneratedMessage; import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.concrete.GlobalCryptoSetup; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; import meerkat.protobuf.Voting; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECPoint; import org.junit.Before; import org.junit.Test; import prover.Prover; @@ -22,87 +14,16 @@ import qilin.primitives.RandomOracle; import qilin.primitives.concrete.DigestOracle; import qilin.primitives.concrete.ECElGamal; import qilin.primitives.concrete.ECGroup; -import qilin.primitives.generic.ElGamal; -import qilin.util.Pair; import verifier.Verifier; - -import java.io.ByteArrayInputStream; import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; import java.util.Random; -import static org.junit.Assert.assertEquals; - /** * Created by Tzlil on 12/31/2015. */ public class ZeroKnowledgeProofTest { - - public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; - /** - * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} - * @param pk - * @return - */ - public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { - ECPoint pkPoint = pk.getPK(); - ECParameterSpec params = group.getCurveParams(); - - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); - - try { - KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); - PublicKey javaPk = fact.generatePublic(pubKeySpec); - ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() - .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); - - return serializedPk; - } catch (Exception e) { - throw new RuntimeException("Error converting public key!", e); - } - } - - /** - * Standard (non-threshold) decryption for testing purposes. - * @param secretKey - * @return - */ - public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) - throws InvalidProtocolBufferException { - ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); - ByteString c1encoded = cipherText.getC1(); - ByteString c2encoded = cipherText.getC2(); - - ECPoint c1 = group.decode(c1encoded.toByteArray()); - ECPoint c2 = group.decode(c2encoded.toByteArray()); - - assert (group.contains(c1)); - assert (group.contains(c2)); - - ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); - - byte[] plaintext = group.injectiveDecode(plaintextEncoded); - - ByteArrayInputStream in = new ByteArrayInputStream(plaintext); - - try { - java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); - builder.mergeDelimitedFrom(in); - return plaintextMessageType.cast(builder.build()); - } catch (Exception e) { - throw new InvalidProtocolBufferException("Plaintext protobuf error"); - } - } - - - Random rand = new Random(0); // Insecure deterministic random for testing. - + Random rand; ECElGamal.SK key; ECGroup group; ECElGamalEncryption enc; @@ -112,14 +33,12 @@ public class ZeroKnowledgeProofTest { @Before public void setup() throws Exception { + rand = new Random(); group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = serializePk(group, key); - - + serializedPk = Utiles.serializePk(group, key); enc = new ECElGamalEncryption(); - enc.init(serializedPk); RandomOracle randomOracle = new DigestOracle(); verifier = new Verifier(enc,randomOracle); @@ -127,23 +46,13 @@ public class ZeroKnowledgeProofTest { } - Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { - Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); - ballot.setSerialNumber(rand.nextInt(1000000)); - for (int i = 0; i < numQuestions; ++i) { - Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); - for (int j = 0; j < numAnswers; ++j) { - answers.addAnswer(rand.nextInt(maxAnswer)); - } - } - return ballot.build(); - } + public void oneZKPTest() throws InvalidProtocolBufferException { - Voting.PlaintextBallot msg1 = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - Voting.PlaintextBallot msg2 = genRandomBallot(2,3,16); + Voting.PlaintextBallot msg1 = Utiles.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Voting.PlaintextBallot msg2 = Utiles.genRandomBallot(2,3,16); Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand); Crypto.EncryptionRandomness r2 = enc.generateRandomness(rand); @@ -151,10 +60,10 @@ public class ZeroKnowledgeProofTest { Crypto.RerandomizableEncryptedMessage e2 = enc.encrypt(msg2, enc.generateRandomness(rand)); Crypto.RerandomizableEncryptedMessage e1Tag = enc.rerandomize(e1, r1); Crypto.RerandomizableEncryptedMessage e2Tag = enc.rerandomize(e2, r2); - assert (decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); - assert (decrypt(Voting.PlaintextBallot.class, key, group, e1Tag).equals(msg1)); - assert (decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); - assert (decrypt(Voting.PlaintextBallot.class, key, group, e2Tag).equals(msg2)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1Tag).equals(msg1)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2Tag).equals(msg2)); assert (verifier.verify(e1,e2,e1Tag,e2Tag,prover.prove(e1,e2,e1Tag,e2Tag,false,0,0,0,r1,r2))); } From 9bb2f47b505d41418a93ac08cf206192d1f4cacd Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 17 Jan 2016 20:17:04 +0200 Subject: [PATCH 13/66] last version - main problem was found in RerandomizeTest --- mixer/src/main/java/main/BatchConverter.java | 91 +++++++ mixer/src/main/java/main/BatchHandler.java | 79 ++++++ mixer/src/main/java/main/MainMixing.java | 198 ++------------- .../necessary/AsyncBulletinBoardClient.java | 32 ++- .../java/necessary/BulletinBoardClient.java | 2 +- .../main/java/necessary/CompleteBatch.java | 68 +++++ .../src/main/java/necessary/SignedBatch.java | 54 ---- .../src/main/java/prover/ProofOrganizer.java | 109 ++++---- mixer/src/main/java/prover/Prover.java | 237 +++++++----------- mixer/src/main/java/verifier/Verifier.java | 48 +--- mixer/src/test/java/mixer/MixingText.java | 2 +- .../src/test/java/mixer/RerandomizeTest.java | 85 +++++++ .../java/mixer/ZeroKnowledgeProofTest.java | 41 ++- 13 files changed, 562 insertions(+), 484 deletions(-) create mode 100644 mixer/src/main/java/main/BatchConverter.java create mode 100644 mixer/src/main/java/main/BatchHandler.java create mode 100644 mixer/src/main/java/necessary/CompleteBatch.java delete mode 100644 mixer/src/main/java/necessary/SignedBatch.java create mode 100644 mixer/src/test/java/mixer/RerandomizeTest.java diff --git a/mixer/src/main/java/main/BatchConverter.java b/mixer/src/main/java/main/BatchConverter.java new file mode 100644 index 0000000..0ac2e93 --- /dev/null +++ b/mixer/src/main/java/main/BatchConverter.java @@ -0,0 +1,91 @@ +package main; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import qilin.util.Pair; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Tzlil on 12/17/2015. + */ + +public class BatchConverter { + + private final int n,layers; + public BatchConverter(int n,int layers){ + this.n = n; + this.layers = layers; + } + private ByteString IntegerToByteString(int a){ + return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); + } + + private int ByteString2Integer(ByteString bs) { + return Integer.valueOf(bs.toString()); + } + + public List mixerOutput2BatchData + (Pair mixerOutput) { + + List result = new ArrayList(); + + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(IntegerToByteString(n)) + .build()); + + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.a) { + for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(zkp.toByteString()) + .build()); + } + } + for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.b) { + for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(encryption.toByteString()) + .build()); + } + } + return result; + } + + public Pair batchDataList2MixerOutput + (List batchDataList) throws Exception { + + if (n != ByteString2Integer(batchDataList.remove(0).getData())){ + throw new Exception(); + } + + int nDiv2 = n >>1; + Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; + for (int layer = 0; layer (proofs,encryptions); + + } + +} + diff --git a/mixer/src/main/java/main/BatchHandler.java b/mixer/src/main/java/main/BatchHandler.java new file mode 100644 index 0000000..7e49e6b --- /dev/null +++ b/mixer/src/main/java/main/BatchHandler.java @@ -0,0 +1,79 @@ +package main; + +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import necessary.AsyncBulletinBoardClient; +import necessary.BulletinBoardClient; +import necessary.CompleteBatch; +import qilin.util.Pair; +import verifier.VerifyTable; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by Tzlil on 12/17/2015. + */ +public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback { + + private Pair mixerOutput; + private boolean msgReceived; + private Throwable t; + private CompleteBatch msg; + + private final int n, layers; + private final Mix2ZeroKnowledgeVerifier verifier; + + public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) { + this.mixerOutput = null; + this.n = n; + this.layers = layers; + this.msgReceived = false; + this.t = null; + this.verifier = verifier; + } + + @Override + public void handleCallback(CompleteBatch msg) { + this.msg = msg; + this.msgReceived = true; + } + + @Override + public void handleFailure(Throwable t) { + this.t = t; + this.msgReceived = true; + } + + + public boolean isMsgReceived() { + return msgReceived; + } + + private void convertMessage() throws Exception { + BatchConverter batchConverter = new BatchConverter(n,layers); + mixerOutput = batchConverter.batchDataList2MixerOutput(msg.getBatchDataList()); + } + + public boolean verifyTable() throws Exception { + if (mixerOutput == null) { + convertMessage(); + } + return VerifyTable.verifyTable(verifier, n, mixerOutput); + } + + public List getInputForMixer() throws Throwable { + if (t != null) { + throw t; + } + if (mixerOutput == null) { + convertMessage(); + if (!VerifyTable.verifyTable(verifier, n, mixerOutput)) { + throw new Exception("in valid table"); + } + } + return Arrays.asList(mixerOutput.b[mixerOutput.b.length - 1]); + } +} + diff --git a/mixer/src/main/java/main/MainMixing.java b/mixer/src/main/java/main/MainMixing.java index ab832d7..a37c604 100644 --- a/mixer/src/main/java/main/MainMixing.java +++ b/mixer/src/main/java/main/MainMixing.java @@ -1,7 +1,5 @@ package main; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.crypto.mixnet.Mixer; import meerkat.protobuf.BulletinBoardAPI; @@ -9,13 +7,10 @@ import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import necessary.AsyncBulletinBoardClient; import necessary.BulletinBoardClient; -import necessary.SignedBatch; import qilin.util.Pair; -import java.math.BigInteger; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; @@ -24,10 +19,10 @@ import java.util.List; */ public class MainMixing { - private Mixer mixer; - private Mix2ZeroKnowledgeVerifier verifier; - private int n, layers; - private AsyncBulletinBoardClient asyncBulletinBoardClient; + private final Mixer mixer; + private final Mix2ZeroKnowledgeVerifier verifier; + private final int n, layers; + private final AsyncBulletinBoardClient asyncBulletinBoardClient; private final byte[] id; private final int mixerOrder; @@ -43,7 +38,7 @@ public class MainMixing { this.id = id; } - public void main(List prevBatchIds, int batchId, BulletinBoardClient.ClientCallback callback) throws Exception { + public void main(List prevBatchIds, int batchId, AsyncBulletinBoardClient.ClientCallback callback) throws Throwable { List mixerInput; @@ -52,11 +47,14 @@ public class MainMixing { List batchHandlers = new ArrayList(prevBatchIds.size()); BatchHandler currentBatchHandler; for (Integer prevBatchId : prevBatchIds) { - currentBatchHandler = new BatchHandler(n, layers); - asyncBulletinBoardClient.readBatch(id, prevBatchId, currentBatchHandler); + currentBatchHandler = new BatchHandler(n, layers,verifier); + asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); batchHandlers.add(currentBatchHandler); } + // ToDo : assert table continues + // ToDo : assert signature validity + boolean allDone = false; while (!allDone) { try { @@ -64,17 +62,18 @@ public class MainMixing { } catch (InterruptedException e) { // do nothing } - // check all handlers done + // check all handlers messages were received allDone = true; for (BatchHandler batchHandler : batchHandlers) { - allDone &= batchHandler.done; + allDone &= batchHandler.isMsgReceived(); } } // assert all handlers succeeded for (BatchHandler batchHandler : batchHandlers) { - if(batchHandler.e != null) - throw batchHandler.e; + if(!batchHandler.verifyTable()){ + throw new Exception("invalid input"); + } } BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); @@ -93,177 +92,14 @@ public class MainMixing { private void updateBB(Pair mixerOutput - , int batchId, BulletinBoardClient.ClientCallback callback) { + , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { - BatchConverter batchConverter = new BatchConverter(); + BatchConverter batchConverter = new BatchConverter(n,layers); List batchDataList = batchConverter.mixerOutput2BatchData(mixerOutput); asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); } - private class BatchConverter { - - ByteString IntegerToByteString(int a){ - return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); - } - - int ByteString2Integer(ByteString bs) { - return Integer.valueOf(bs.toString()); - } - - List mixerOutput2BatchData - (Pair mixerOutput) { - - List result = new ArrayList(); - - // - - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(IntegerToByteString(n)) - .build()); - - for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.a) { - for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(zkp.toByteString()) - .build()); - } - } - for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.b) { - for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(encryption.toByteString()) - .build()); - } - } - return result; - } - Pair batchDataList2MixerOutput - (List batchDataList) throws Exception { - - if (n != ByteString2Integer(batchDataList.remove(0).getData())){ - throw new Exception(); - } - - int nDiv2 = n >>1; - Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; - for (int layer = 0; layer (proofs,encryptions); - - } - - } - private class BatchHandler implements BulletinBoardClient.ClientCallback { - - public Pair mixerOutput; - public boolean done; - private int n,layers; - private Exception e; - - public BatchHandler(int n, int layers) { - this.n = n; - this.layers = layers; - done = false; - e = null; - } - - // convert batch message to MixerInput - // and verify it - @Override - public void handleCallback(SignedBatch msg) { - BatchConverter batchConverter = new BatchConverter(); - try { - mixerOutput = batchConverter.batchDataList2MixerOutput(msg.getBatchDataList()); - done = verifyTable(); - } catch (Exception e) { - this.e = e; - done = true; - } - } - - @Override - public void handleFailure(Throwable t) { - - } - - private boolean verifyTable() throws InvalidProtocolBufferException { - int index1,index2,layer; - - //initialize locationChecksum table - // use for check BeneshNet validity - boolean[][] locationChecksum = new boolean[layers][n]; - for (boolean[] locationChecksumLayer: locationChecksum) { - Arrays.fill(locationChecksumLayer,false); - } - - Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.a; - Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.b; - - for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { - for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { - Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); - index1 = location.getI(); - index2 = location.getJ(); - layer = location.getLayer(); - - // check location validity - if (layer > layers >> 1) { - if (index2 - index1 != n >> (layers - layer)) - return false; - } - else{ - if (index2 - index1 != n >> (layer + 1)) - return false; - } - - // mark location in table - locationChecksum[layer][index1] = true; - locationChecksum[layer][index2] = true; - - // verify proof - if(!verifier.verify(rerandomizableEncryptedMessages[index1][layer], - rerandomizableEncryptedMessages[index2][layer], - rerandomizableEncryptedMessages[index1][layer + 1], - rerandomizableEncryptedMessages[index2][layer + 1], - zkp)) - return false; - } - } - - // verify all necessary locations for BeneshNet were proved - for (boolean[] checksumLayer: locationChecksum) { - for (boolean locationBoolean: checksumLayer) { - if (!locationBoolean) - return false; - } - } - return true; - } - - public List getInputForMixer() - { - return Arrays.asList(mixerOutput.b[mixerOutput.b.length - 1]); - } - } - } diff --git a/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java index b8847f9..6dcc1f1 100644 --- a/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java +++ b/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java @@ -1,21 +1,30 @@ package necessary; - import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.BulletinBoardAPI.*; - import java.util.List; +import java.util.List; /** * Created by Arbel Deutsch Peled on 14-Dec-15. */ public interface AsyncBulletinBoardClient extends BulletinBoardClient { + public interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + public interface MessageHandler { + void handleNewMessages(List messageList); + } + /** * Post a message to the bulletin board in an asynchronous manner * @param msg is the message to be posted * @param callback is a class containing methods to handle the result of the operation * @return a unique message ID for the message, that can be later used to retrieve the batch */ - MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); /** * This method allows for sending large messages as a batch to the bulletin board @@ -26,12 +35,12 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a callback function class for handling results of the operation * @return a unique message ID for the entire message, that can be later used to retrieve the batch */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); /** * Overloading of the postBatch method in which startPosition is set to the default value 0 */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); /** * Check how "safe" a given message is in an asynchronous manner @@ -39,7 +48,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param id is the unique message identifier for retrieval * @param callback is a callback function class for handling results of the operation */ - void getRedundancy(MessageID id, ClientCallback callback); + public void getRedundancy(MessageID id, ClientCallback callback); /** * Read all messages posted matching the given filter in an asynchronous manner @@ -49,7 +58,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering). * @param callback is a callback function class for handling results of the operation */ - void readMessages(MessageFilterList filterList, ClientCallback> callback); + public void readMessages(MessageFilterList filterList, ClientCallback> callback); /** * Read a given batch message from the bulletin board @@ -57,6 +66,13 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param batchId is the unique (per signer) ID of the batch * @param callback is a callback class for handling the result of the operation */ - void readBatch(byte[] signerId, int batchId, ClientCallback callback); + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * @param filterList defines the set of filters for message retrieval + * @param messageHandler defines the handler for new messages received + */ + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); } diff --git a/mixer/src/main/java/necessary/BulletinBoardClient.java b/mixer/src/main/java/necessary/BulletinBoardClient.java index 6442c40..d8f9f28 100644 --- a/mixer/src/main/java/necessary/BulletinBoardClient.java +++ b/mixer/src/main/java/necessary/BulletinBoardClient.java @@ -56,7 +56,7 @@ public interface BulletinBoardClient { /** * Closes all connections, if any. - * This is done in a synchronous (blocking) way. + * This is msgRecived in a synchronous (blocking) way. */ void close(); diff --git a/mixer/src/main/java/necessary/CompleteBatch.java b/mixer/src/main/java/necessary/CompleteBatch.java new file mode 100644 index 0000000..d108a7d --- /dev/null +++ b/mixer/src/main/java/necessary/CompleteBatch.java @@ -0,0 +1,68 @@ +package necessary; + + + import meerkat.protobuf.BulletinBoardAPI.*; + import meerkat.protobuf.Crypto.*; + + import java.util.LinkedList; + import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * A data structure for holding a complete batch message along with its signature + */ +public class CompleteBatch { + + private BeginBatchMessage beginBatchMessage; + private List batchDataList; + private Signature signature; + + public CompleteBatch() { + batchDataList = new LinkedList(); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { + this(); + beginBatchMessage = newBeginBatchMessage; + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList) { + this(newBeginBatchMessage); + appendBatchData(newDataList); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature) { + this(newBeginBatchMessage, newDataList); + signature = newSignature; + } + + public BeginBatchMessage getBeginBatchMessage() { + return beginBatchMessage; + } + + public List getBatchDataList() { + return batchDataList; + } + + public Signature getSignature() { + return signature; + } + + public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { + this.beginBatchMessage = beginBatchMessage; + } + + public void appendBatchData(BatchData newBatchData) { + batchDataList.add(newBatchData); + } + + public void appendBatchData(List newBatchDataList) { + batchDataList.addAll(newBatchDataList); + } + + public void setSignature(Signature newSignature) { + signature = newSignature; + } + +} diff --git a/mixer/src/main/java/necessary/SignedBatch.java b/mixer/src/main/java/necessary/SignedBatch.java deleted file mode 100644 index 6aecebf..0000000 --- a/mixer/src/main/java/necessary/SignedBatch.java +++ /dev/null @@ -1,54 +0,0 @@ -package necessary; - -/** - * Created by Tzlil on 12/27/2015. - */ - - import meerkat.protobuf.BulletinBoardAPI.*; - import meerkat.protobuf.Crypto.*; - - import java.util.LinkedList; - import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 14-Dec-15. - * - * A data structure for holding both a batch message and its signature - */ -public class SignedBatch { - - private List batchDataList; - private Signature signature; - - public SignedBatch() { - batchDataList = new LinkedList(); - } - - public SignedBatch(List newDataList) { - this(); - appendBatchData(newDataList); - } - - public SignedBatch(List newDataList, Signature newSignature) { - this(newDataList); - signature = newSignature; - } - - public List getBatchDataList() { - return batchDataList; - } - - public Signature getSignature() { - return signature; - } - - public void appendBatchData(BatchData newBatchData) { - batchDataList.add(newBatchData); - } - - public void appendBatchData(List newBatchDataList) { - batchDataList.addAll(newBatchDataList); - } - - -} diff --git a/mixer/src/main/java/prover/ProofOrganizer.java b/mixer/src/main/java/prover/ProofOrganizer.java index 3dae29c..16b032b 100644 --- a/mixer/src/main/java/prover/ProofOrganizer.java +++ b/mixer/src/main/java/prover/ProofOrganizer.java @@ -7,70 +7,79 @@ import meerkat.protobuf.Crypto; */ public class ProofOrganizer { - private final Crypto.RerandomizableEncryptedMessage e1; - private final Crypto.RerandomizableEncryptedMessage e2; - private final Crypto.RerandomizableEncryptedMessage e1New; - private final Crypto.RerandomizableEncryptedMessage e2New; + private final OrProofInput first; + private final OrProofInput second; + private final OrProofInput third; + private final OrProofInput fourth; + + protected ProofOrganizer(Crypto.RerandomizableEncryptedMessage e1,Crypto.RerandomizableEncryptedMessage e2 + ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New + ,Crypto.EncryptionRandomness r1,Crypto.EncryptionRandomness r2,boolean switched) { + if(!switched) { + this.first = new OrProofInput(e1, e1New, e2, e1New, r1,TrueCouple.left); + this.second = new OrProofInput(e1, e1New, e1, e2New,r1,TrueCouple.left); + this.third = new OrProofInput(e2, e1New, e2, e2New,r2,TrueCouple.right); + this.fourth = new OrProofInput(e1, e2New, e2, e2New,r2,TrueCouple.right); + }else{ + this.first = new OrProofInput(e1, e1New, e2, e1New, r2,TrueCouple.right); + this.second = new OrProofInput(e1, e1New, e1, e2New,r1,TrueCouple.right); + this.third = new OrProofInput(e2, e1New, e2, e2New,r2,TrueCouple.left); + this.fourth = new OrProofInput(e1, e2New, e2, e2New,r1,TrueCouple.left); + } + + } - //in1, out1, in2, out1, - //in1, out1, in1, out2 - //in2, out1, in2, out2, - //in1, out2, in2, out2 public ProofOrganizer(Crypto.RerandomizableEncryptedMessage e1,Crypto.RerandomizableEncryptedMessage e2 - ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New) - { - this.e1 = e1; - this.e2 = e2; - this.e1New = e1New; - this.e2New = e2New; - + ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New) { + this.first = new OrProofInput(e1, e1New, e2, e1New, null,TrueCouple.unknown); + this.second = new OrProofInput(e1, e1New, e1, e2New,null,TrueCouple.unknown); + this.third = new OrProofInput(e2, e1New, e2, e2New,null,TrueCouple.unknown); + this.fourth = new OrProofInput(e1, e2New, e2, e2New,null,TrueCouple.unknown); } public enum OrProofOrder{ first,second,third,fourth } - public Crypto.RerandomizableEncryptedMessage getE1(OrProofOrder orProofOrder) - { - switch (orProofOrder){ - case third: - return e2; - default: - return e1; - } - + public enum TrueCouple{ + left,right,unknown } - public Crypto.RerandomizableEncryptedMessage getE1New(OrProofOrder orProofOrder) - { + + public OrProofInput getOrProofInput(OrProofOrder orProofOrder){ switch (orProofOrder){ - case fourth: - return e2New; - default: - return e1New; - } - } - - public Crypto.RerandomizableEncryptedMessage getE2(OrProofOrder orProofOrder) - { - switch (orProofOrder){ - case second: - return e1; - default: - return e2; - } - - } - - public Crypto.RerandomizableEncryptedMessage getE2New(OrProofOrder orProofOrder) - { - switch (orProofOrder){ case first: - return e1New; - default: - return e2New; + return this.first; + case second: + return this.second; + case third: + return this.third; + case fourth: + return this.fourth; } + return null; + } + public class OrProofInput{ + + + public final Crypto.RerandomizableEncryptedMessage e1; + public final Crypto.RerandomizableEncryptedMessage e1New; + public final Crypto.RerandomizableEncryptedMessage e2; + public final Crypto.RerandomizableEncryptedMessage e2New; + protected final Crypto.EncryptionRandomness x; + protected final TrueCouple flag; + + private OrProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e1New, + Crypto.RerandomizableEncryptedMessage e2, Crypto.RerandomizableEncryptedMessage e2New, + Crypto.EncryptionRandomness x, TrueCouple flag) { + this.e1 = e1; + this.e1New = e1New; + this.e2 = e2; + this.e2New = e2New; + this.x = x; + this.flag = flag; + } } } diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 7712a41..5cbd2c0 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -5,6 +5,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -13,6 +14,7 @@ import qilin.primitives.RandomOracle; import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; +import java.util.List; import java.util.Random; public class Prover implements Mix2ZeroKnowledgeProver { @@ -23,8 +25,6 @@ public class Prover implements Mix2ZeroKnowledgeProver { ECElGamalEncryption ecElGamalEncryption; ECPoint g,h; - Mix2ZeroKnowledgeVerifier verifier; - public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { this.rand = rand; @@ -33,20 +33,6 @@ public class Prover implements Mix2ZeroKnowledgeProver { this.group = ecElGamalEncryption.getGroup(); this.g = group.getGenerator(); this.h = ecElGamalEncryption.getElGamalPK().getPK(); - - verifier = null; - } - - public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle,Mix2ZeroKnowledgeVerifier verifier) { - - this.rand = rand; - this.ecElGamalEncryption = encryptor; - this.randomOracle = randomOracle; - this.group = ecElGamalEncryption.getGroup(); - this.g = group.getGenerator(); - this.h = ecElGamalEncryption.getElGamalPK().getPK(); - - this.verifier = verifier; } @@ -60,58 +46,23 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; - ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2); - if (!sw) - { - first = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), - organizer.getE2(ProofOrganizer.OrProofOrder.first), - organizer.getE1New(ProofOrganizer.OrProofOrder.first), - organizer.getE2New(ProofOrganizer.OrProofOrder.first), - r1, true); - second = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), - organizer.getE2(ProofOrganizer.OrProofOrder.second), - organizer.getE1New(ProofOrganizer.OrProofOrder.second), - organizer.getE2New(ProofOrganizer.OrProofOrder.second), r1, true); - third = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), - organizer.getE2(ProofOrganizer.OrProofOrder.third), - organizer.getE1New(ProofOrganizer.OrProofOrder.third), - organizer.getE2New(ProofOrganizer.OrProofOrder.third), r2, false); - fourth = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2(ProofOrganizer.OrProofOrder.fourth), - organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), r2, false); - } - else - { - first = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), - organizer.getE2(ProofOrganizer.OrProofOrder.first), - organizer.getE1New(ProofOrganizer.OrProofOrder.first), - organizer.getE2New(ProofOrganizer.OrProofOrder.first), - r2, false); - second = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), - organizer.getE2(ProofOrganizer.OrProofOrder.second), - organizer.getE1New(ProofOrganizer.OrProofOrder.second), - organizer.getE2New(ProofOrganizer.OrProofOrder.second), - r1, false); - third = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), - organizer.getE2(ProofOrganizer.OrProofOrder.third), - organizer.getE1New(ProofOrganizer.OrProofOrder.third), - organizer.getE2New(ProofOrganizer.OrProofOrder.third), - r2, true); - fourth = createOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2(ProofOrganizer.OrProofOrder.fourth), - organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), - r1, true); - } + ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2,r1,r2,sw); + + System.out.println("first"); + first = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.first)); + System.out.println("second"); + second = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.second)); + System.out.println("third"); + third = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.third)); + System.out.println("fourth"); + fourth = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.fourth)); + Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() .setI(i) .setJ(j) .setLayer(layer) .build(); - - Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() .setFirst(first) .setSecond(second) @@ -120,31 +71,18 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setLocation(location) .build(); - //debuging - if (verifier != null){ - if (!verifier.verify(in1,in2,out1,out2,result)){ - - System.out.print(location.toString()); - System.out.println("switch value : " + sw); - } - } - return result; } - private Mixing.ZeroKnowledgeProof.OrProof createOrProof(Crypto.RerandomizableEncryptedMessage e1, - Crypto.RerandomizableEncryptedMessage e2, - Crypto.RerandomizableEncryptedMessage e1New, - Crypto.RerandomizableEncryptedMessage e2New, - Crypto.EncryptionRandomness x, - boolean flag) throws InvalidProtocolBufferException { + private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ProofOrganizer.OrProofInput orProofInput) + throws InvalidProtocolBufferException { - ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); - ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); - ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); - ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1); + ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2); + ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1New); + ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2New); - return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,x,flag); + return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProofInput.x,orProofInput.flag); } @@ -163,7 +101,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { ElGamalCiphertext e1New, ElGamalCiphertext e2New, Crypto.EncryptionRandomness x, - boolean flag) { + ProofOrganizer.TrueCouple flag) { ECPoint g1 = g; ECPoint h1 = group.add(convert2ECPoint(e1New.getC1()),group.negate(convert2ECPoint(e1.getC1()))); @@ -178,68 +116,79 @@ public class Prover implements Mix2ZeroKnowledgeProver { BigInteger r = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); BigInteger c1,c2,z,zTag; ECPoint u,v,uTag,vTag; - if (flag) - { - c2 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - zTag = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - //step 1 - u = group.multiply(g1, r); - v = group.multiply(g2, r); - uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); - vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); - //step 2 - // c1 = (hash(input + step1) + group size - c2)% group size - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(group.encode(g1))) - .setH1(ByteString.copyFrom(group.encode(h1))) - .setG2(ByteString.copyFrom(group.encode(g2))) - .setH2(ByteString.copyFrom(group.encode(h2))) - .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) - .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) - .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) - .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) - .setU(ByteString.copyFrom(group.encode(u))) - .setV(ByteString.copyFrom(group.encode(v))) - .setUTag(ByteString.copyFrom(group.encode(uTag))) - .setVTag(ByteString.copyFrom(group.encode(vTag))) - .build(); - c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); - //step 3 - //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); - } - else - { - c1 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - z = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - //step 1 - uTag = group.multiply(g1Tag, r); - vTag = group.multiply(g2Tag, r); - u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); - v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); - //step 2 - // c1 = (hash(input + step1) + group size - c1)% group size - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(group.encode(g1))) - .setH1(ByteString.copyFrom(group.encode(h1))) - .setG2(ByteString.copyFrom(group.encode(g2))) - .setH2(ByteString.copyFrom(group.encode(h2))) - .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) - .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) - .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) - .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) - .setU(ByteString.copyFrom(group.encode(u))) - .setV(ByteString.copyFrom(group.encode(v))) - .setUTag(ByteString.copyFrom(group.encode(uTag))) - .setVTag(ByteString.copyFrom(group.encode(vTag))) - .build(); - c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); - //step 3 - //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + switch (flag) { + case left: + c2 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + zTag = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + //step 1 + u = group.multiply(g1, r); + v = group.multiply(g2, r); + uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); + vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); + //step 2 + // c1 = (hash(input + step1) + group size - c2)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(group.encode(g1))) + .setH1(ByteString.copyFrom(group.encode(h1))) + .setG2(ByteString.copyFrom(group.encode(g2))) + .setH2(ByteString.copyFrom(group.encode(h2))) + .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) + .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) + .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) + .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); + //step 3 + //z = (r + c1 * x) % group size; + z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); + break; + case right: + c1 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + z = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + //step 1 + uTag = group.multiply(g1Tag, r); + vTag = group.multiply(g2Tag, r); + u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); + v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); + //step 2 + // c1 = (hash(input + step1) + group size - c1)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(group.encode(g1))) + .setH1(ByteString.copyFrom(group.encode(h1))) + .setG2(ByteString.copyFrom(group.encode(g2))) + .setH2(ByteString.copyFrom(group.encode(h2))) + .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) + .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) + .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) + .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); + //step 3 + //zTag = (r + c2 * x) % group size; + zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); + break; + default: + return null; } + + //debugging + assert (group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1)))); + assert (group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1)))); + assert (group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2)))); + assert (group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2)))); + + return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() .setG1(ByteString.copyFrom(group.encode(g1))) .setH1(ByteString.copyFrom(group.encode(h1))) diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index c8c9914..977abfc 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -59,41 +59,20 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2); - return verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.first), - organizer.getE2(ProofOrganizer.OrProofOrder.first), - organizer.getE1New(ProofOrganizer.OrProofOrder.first), - organizer.getE2New(ProofOrganizer.OrProofOrder.first), - proof.getFirst(),ProofOrganizer.OrProofOrder.first)&& - verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.second), - organizer.getE2(ProofOrganizer.OrProofOrder.second), - organizer.getE1New(ProofOrganizer.OrProofOrder.second), - organizer.getE2New(ProofOrganizer.OrProofOrder.second), - proof.getSecond(),ProofOrganizer.OrProofOrder.second)&& - verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.third), - organizer.getE2(ProofOrganizer.OrProofOrder.third), - organizer.getE1New(ProofOrganizer.OrProofOrder.third), - organizer.getE2New(ProofOrganizer.OrProofOrder.third), - proof.getThird(),ProofOrganizer.OrProofOrder.third)&& - verifyOrProof(organizer.getE1(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2(ProofOrganizer.OrProofOrder.fourth), - organizer.getE1New(ProofOrganizer.OrProofOrder.fourth), - organizer.getE2New(ProofOrganizer.OrProofOrder.fourth), - proof.getFourth(),ProofOrganizer.OrProofOrder.fourth); + return verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.first), proof.getFirst())&& + verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.second), proof.getSecond())&& + verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.third), proof.getThird())&& + verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.fourth), proof.getFourth()); + } - - - public boolean verifyOrProof(Crypto.RerandomizableEncryptedMessage e1, - Crypto.RerandomizableEncryptedMessage e2, - Crypto.RerandomizableEncryptedMessage e1Tag, - Crypto.RerandomizableEncryptedMessage e2Tag, - Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) throws InvalidProtocolBufferException { - - ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); - ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); - ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1Tag); - ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2Tag); - return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProof,orProofOrder); + public boolean verifyOrProof(ProofOrganizer.OrProofInput orProofInput, Mixing.ZeroKnowledgeProof.OrProof orProof) + throws InvalidProtocolBufferException { + ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1); + ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2); + ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1New); + ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2New); + return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProof); } @@ -173,7 +152,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { ElGamalCiphertext e2, ElGamalCiphertext e1New, ElGamalCiphertext e2New, - Mixing.ZeroKnowledgeProof.OrProof orProof, ProofOrganizer.OrProofOrder orProofOrder) + Mixing.ZeroKnowledgeProof.OrProof orProof) { parseOrProof(orProof); List conditions = createConditionsList(e1,e2,e1New,e2New); @@ -184,7 +163,6 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { if (result){ result = false; System.out.print("\n\n\n"); - System.out.println(orProofOrder.toString()); } System.out.println(condition.errorDescripton); } diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index a4b9c81..ac05513 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -50,7 +50,7 @@ public class MixingText { randomProver = new Random(); randomOracle = new DigestOracle(); verifier = new Verifier(encryptor,randomOracle); - prover = new Prover(randomProver,encryptor,randomOracle,verifier); + prover = new Prover(randomProver,encryptor,randomOracle); mixer = new Mixer(randomMixer,prover,encryptor); // generate n diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java new file mode 100644 index 0000000..6e29bb5 --- /dev/null +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -0,0 +1,85 @@ +package mixer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import verifier.Verifier; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/17/2016. + */ +public class RerandomizeTest { + + Random rand; + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + ECPoint g ; + ECPoint h ; + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + RandomOracle randomOracle = new DigestOracle(); + g = group.getGenerator(); + h = enc.getElGamalPK().getPK(); + } + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + public void oneRerandomizeTest() throws InvalidProtocolBufferException { + Voting.PlaintextBallot msg = Utiles.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + + Crypto.EncryptionRandomness r = enc.generateRandomness(rand); + + + Crypto.RerandomizableEncryptedMessage e = enc.encrypt(msg, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage eNew = enc.rerandomize(e, r); + + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg)); + + ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e); + ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(eNew); + + assert (g.multiply(new BigInteger(r.getData().toByteArray())).equals( + group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))))); + assert (h.multiply(new BigInteger(r.getData().toByteArray())).equals( + group.add(convert2ECPoint(eNewElGamal.getC2()), group.negate(convert2ECPoint(eElGamal.getC2()))))); + } + + @Test + public void rerandomizeTest() throws InvalidProtocolBufferException { + + int tests = 1000; + + for (int i = 0; i < tests; i ++){ + System.out.println("rerandomiz test #" + i); + oneRerandomizeTest(); + } + } +} diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index 9c50f74..a0952e2 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -1,5 +1,6 @@ package mixer; +import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; @@ -7,6 +8,7 @@ import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; +import org.bouncycastle.math.ec.ECPoint; import org.junit.Before; import org.junit.Test; import prover.Prover; @@ -45,12 +47,11 @@ public class ZeroKnowledgeProofTest { prover = new Prover(new Random(),enc,randomOracle); } - - - + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } public void oneZKPTest() throws InvalidProtocolBufferException { - Voting.PlaintextBallot msg1 = Utiles.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. Voting.PlaintextBallot msg2 = Utiles.genRandomBallot(2,3,16); Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand); @@ -58,13 +59,33 @@ public class ZeroKnowledgeProofTest { Crypto.RerandomizableEncryptedMessage e1 = enc.encrypt(msg1, enc.generateRandomness(rand)); Crypto.RerandomizableEncryptedMessage e2 = enc.encrypt(msg2, enc.generateRandomness(rand)); - Crypto.RerandomizableEncryptedMessage e1Tag = enc.rerandomize(e1, r1); - Crypto.RerandomizableEncryptedMessage e2Tag = enc.rerandomize(e2, r2); + Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1); + Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1Tag).equals(msg1)); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1New).equals(msg1)); assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2Tag).equals(msg2)); - assert (verifier.verify(e1,e2,e1Tag,e2Tag,prover.prove(e1,e2,e1Tag,e2Tag,false,0,0,0,r1,r2))); + assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2New).equals(msg2)); + + ECPoint g = group.getGenerator(); + ECPoint h = enc.getElGamalPK().getPK(); + + ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ConcreteCrypto.ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); + ConcreteCrypto.ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + + + assert (g.multiply(new BigInteger(r1.getData().toByteArray())).equals( + group.add(convert2ECPoint(e1TagElGamal.getC1()),group.negate(convert2ECPoint(e1ElGamal.getC1()))))); + assert (h.multiply(new BigInteger(r1.getData().toByteArray())).equals( + group.add(convert2ECPoint(e1TagElGamal.getC2()),group.negate(convert2ECPoint(e1ElGamal.getC2()))))); + assert (g.multiply(new BigInteger(r2.getData().toByteArray())).equals( + group.add(convert2ECPoint(e2TagElGamal.getC1()),group.negate(convert2ECPoint(e2ElGamal.getC1()))))); + assert (h.multiply(new BigInteger(r2.getData().toByteArray())).equals( + group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))))); + + assert (verifier.verify(e1,e2,e1New,e2New,prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2))); } @Test @@ -73,7 +94,7 @@ public class ZeroKnowledgeProofTest { int tests = 1000; for (int i = 0; i < tests; i ++){ - System.out.println("test " + i); + System.out.println("ZKP test #" + i); oneZKPTest(); } } From ae2b7c51f0e38f5c13af1beba6d404241589e025 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Wed, 20 Jan 2016 12:14:15 +0200 Subject: [PATCH 14/66] zkp speedup --- .../java/meerkat/crypto/mixnet/Mixer.java | 4 +- .../meerkat/crypto/mixnet/MixerOutput.java | 13 + mixer/src/main/java/main/BatchConverter.java | 12 +- mixer/src/main/java/main/BatchHandler.java | 5 +- mixer/src/main/java/main/MainMixing.java | 6 +- mixer/src/main/java/mixer/Mixer.java | 68 +++-- mixer/src/main/java/mixer/MixerOutput.java | 109 ++++++++ .../java/prover/ElGamalProofOrganizer.java | 239 ++++++++++++++++++ .../src/main/java/prover/ProofOrganizer.java | 85 ------- mixer/src/main/java/prover/Prover.java | 136 ++++------ mixer/src/main/java/verifier/Verifier.java | 60 ++--- mixer/src/main/java/verifier/VerifyTable.java | 9 +- .../src/test/java/mixer/CreateTestVector.java | 100 ++++++++ mixer/src/test/java/mixer/MixingText.java | 25 +- .../src/test/java/mixer/RerandomizeTest.java | 4 +- .../ECGroupProfiling/AddProfiling.java | 65 +++++ .../ECGroupProfiling/EncodeProfiling.java | 59 +++++ .../ECGroupProfiling/MulProfiling.java | 81 ++++++ .../ECGroupProfiling/NegateProfiling.java | 59 +++++ .../java/profiling/RerandomizeProfiling.java | 79 ++++++ .../ZeroKnowledgeProofProfiling.java | 87 +++++++ 21 files changed, 1056 insertions(+), 249 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java create mode 100644 mixer/src/main/java/mixer/MixerOutput.java create mode 100644 mixer/src/main/java/prover/ElGamalProofOrganizer.java delete mode 100644 mixer/src/main/java/prover/ProofOrganizer.java create mode 100644 mixer/src/test/java/mixer/CreateTestVector.java create mode 100644 mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java create mode 100644 mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java create mode 100644 mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java create mode 100644 mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java create mode 100644 mixer/src/test/java/profiling/RerandomizeProfiling.java create mode 100644 mixer/src/test/java/profiling/ZeroKnowledgeProofProfiling.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index dc2f819..5a0834f 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -11,6 +11,6 @@ import java.util.List; * Created by talm on 25/10/15. */ public interface Mixer { - public Pair - mix(List ciphertexts) throws InvalidProtocolBufferException; + public MixerOutput mix(List ciphertexts) + throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java new file mode 100644 index 0000000..9ae1432 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java @@ -0,0 +1,13 @@ +package meerkat.crypto.mixnet; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Created by Tzlil on 1/18/2016. + */ +public interface MixerOutput { + public Mixing.ZeroKnowledgeProof[][] gerProofs(); + public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages(); + public int getN(); +} diff --git a/mixer/src/main/java/main/BatchConverter.java b/mixer/src/main/java/main/BatchConverter.java index 0ac2e93..008c868 100644 --- a/mixer/src/main/java/main/BatchConverter.java +++ b/mixer/src/main/java/main/BatchConverter.java @@ -1,6 +1,7 @@ package main; import com.google.protobuf.ByteString; +import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -29,8 +30,7 @@ public class BatchConverter { return Integer.valueOf(bs.toString()); } - public List mixerOutput2BatchData - (Pair mixerOutput) { + public List mixerOutput2BatchData(MixerOutput mixerOutput) { List result = new ArrayList(); @@ -38,14 +38,14 @@ public class BatchConverter { .setData(IntegerToByteString(n)) .build()); - for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.a) { + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.gerProofs()) { for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { result.add(BulletinBoardAPI.BatchData.newBuilder() .setData(zkp.toByteString()) .build()); } } - for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.b) { + for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.getEncryptedMessages()) { for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { result.add(BulletinBoardAPI.BatchData.newBuilder() .setData(encryption.toByteString()) @@ -55,7 +55,7 @@ public class BatchConverter { return result; } - public Pair batchDataList2MixerOutput + public MixerOutput batchDataList2MixerOutput (List batchDataList) throws Exception { if (n != ByteString2Integer(batchDataList.remove(0).getData())){ @@ -83,7 +83,7 @@ public class BatchConverter { } } - return new Pair(proofs,encryptions); + return new mixer.MixerOutput(n,layers,proofs,encryptions); } diff --git a/mixer/src/main/java/main/BatchHandler.java b/mixer/src/main/java/main/BatchHandler.java index 7e49e6b..d20d369 100644 --- a/mixer/src/main/java/main/BatchHandler.java +++ b/mixer/src/main/java/main/BatchHandler.java @@ -1,6 +1,7 @@ package main; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import necessary.AsyncBulletinBoardClient; @@ -17,7 +18,7 @@ import java.util.List; */ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback { - private Pair mixerOutput; + private MixerOutput mixerOutput; private boolean msgReceived; private Throwable t; private CompleteBatch msg; @@ -73,7 +74,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback mixerOutput - = mixer.mix(mixerInput); + MixerOutput mixerOutput = mixer.mix(mixerInput); updateBB(mixerOutput, batchId, callback); } - private void updateBB(Pair mixerOutput + private void updateBB(MixerOutput mixerOutput , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { BatchConverter batchConverter = new BatchConverter(n,layers); diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 1de3a91..51a7950 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -1,9 +1,13 @@ package mixer; +import java.math.*; +import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import qilin.primitives.concrete.ECGroup; import qilin.util.Pair; import java.util.Random; @@ -30,8 +34,14 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { this.verifier = null; } + public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc,Mix2ZeroKnowledgeVerifier verifier) { + this.random = rand; + this.prover = prov; + this.encryptor = enc; + this.verifier = verifier; + } - public Pair mix(List ciphertexts) throws InvalidProtocolBufferException { + public MixerOutput mix(List ciphertexts) throws InvalidProtocolBufferException { int n = ciphertexts.size(); int nDiv2 = n >> 1; @@ -42,7 +52,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { //initialization int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; - ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][n]; int index1, index2, switchIndex = 0; EncryptionRandomness r1, r2; RerandomizableEncryptedMessage e1, e2; @@ -50,12 +60,14 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { MixNetwork mixNetwork = new MixNetwork(new RandomPermutation(n,random)); Switch[] switchesLayer; - // set first level of encryption + EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; + // set first level of encryption for (int j = 0; j < n; j++) { encryptionTable[0][j] = ciphertexts.get(j); } + BigInteger time = BigInteger.valueOf(System.currentTimeMillis()); // main loop for (int layer = 0; layer < layers; layer++) { @@ -65,25 +77,45 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { index2 = sw.j; e1 = encryptionTable[layer][index1]; e2 = encryptionTable[layer][index2]; - r1 = encryptor.generateRandomness(random); - r2 = encryptor.generateRandomness(random); - if (!sw.value) { - encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); - encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); - } else { - encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); - encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); - } - proofsTable[layer][switchIndex] = - prover.prove(e1, e2, encryptionTable[layer + 1][index1], - encryptionTable[layer + 1][index2], - sw.value, sw.i,sw.j,sw.layer, r1, r2); + r1 = encryptor.generateRandomness(random); + r2 = encryptor.generateRandomness(random); + if (!sw.value) { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); - switchIndex = (switchIndex + 1) % nDiv2; + } else { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); + } + randomnesses[layer][index1] = r1; + randomnesses[layer][index2] = r2; } } - return new Pair(proofsTable, encryptionTable); + System.out.println("re enc time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); + time = BigInteger.valueOf(System.currentTimeMillis()); + // main loop + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; + + proofsTable[layer][switchIndex] = + prover.prove(e1, e2, encryptionTable[layer + 1][index1], + encryptionTable[layer + 1][index2], + sw.value, sw.i, sw.j, sw.layer, r1, r2); + + switchIndex = (switchIndex + 1) % nDiv2; + } + } + System.out.println("zkp time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); + return new mixer.MixerOutput(n,layers,proofsTable, encryptionTable); } } \ No newline at end of file diff --git a/mixer/src/main/java/mixer/MixerOutput.java b/mixer/src/main/java/mixer/MixerOutput.java new file mode 100644 index 0000000..38ad3c8 --- /dev/null +++ b/mixer/src/main/java/mixer/MixerOutput.java @@ -0,0 +1,109 @@ +package mixer; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.awt.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; + + +/** + * Created by Tzlil on 1/18/2016. + */ +public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ + private final Mixing.ZeroKnowledgeProof[][] proofs; + private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; + private final int n; + private final int layers; + + public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { + this.proofs = proofs; + this.encryptedMessages = encryptedMessages; + this.n = n; + this.layers = layers; + } + + public MixerOutput(meerkat.crypto.mixnet.MixerOutput mixerOutput) { + this.proofs = mixerOutput.gerProofs(); + this.encryptedMessages = mixerOutput.getEncryptedMessages(); + this.n = mixerOutput.getN(); + this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1; + } + + + @Override + public Mixing.ZeroKnowledgeProof[][] gerProofs() { + return proofs; + } + + @Override + public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() { + return encryptedMessages; + } + + @Override + public int getN() { + return n; + } + + public void outToFile(String dir) throws IOException { + + (new File(dir)).mkdirs(); + //create files + String proofsDir = dir + "/Proofs"; + String encDir = dir + "/EncryptedMessages"; + (new File(proofsDir)).mkdir(); + (new File(encDir)).mkdir(); + for (int layer = 0; layer < layers; layer++){ + (new File(proofsDir +"/layer" + layer )).mkdir(); + (new File(encDir +"/layer" + layer )).mkdir(); + } + (new File(encDir +"/input")).mkdir(); + + + for (int layer = 0; layer < layers; layer++){ + for(int i = 0; i < proofs[layer].length; i ++){ + writeProofToFile(proofsDir,proofs[layer][i]); + } + } + + for (int layer = 0; layer <= layers; layer++){ + for(int i = 0; i < encryptedMessages[layer].length; i ++){ + writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]); + } + } + } + + private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException { + Mixing.ZeroKnowledgeProof.Location location = proof.getLocation(); + int layer = location.getLayer(); + int i = location.getI(); + int j = location.getJ(); + String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(proof.toByteArray()); + fos.close(); + } + + private void writeEncToFile(String encDir,int layer,int i, Crypto.RerandomizableEncryptedMessage enc) throws IOException { + + String fileName; + if(layer >= 0) + fileName = encDir+"/layer" + layer +"/" + i; + else + fileName = encDir+"/input/" + i; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(enc.toByteArray()); + fos.close(); + } +} diff --git a/mixer/src/main/java/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/prover/ElGamalProofOrganizer.java new file mode 100644 index 0000000..cec8256 --- /dev/null +++ b/mixer/src/main/java/prover/ElGamalProofOrganizer.java @@ -0,0 +1,239 @@ +package prover; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.math.ec.ECPoint; +import qilin.primitives.concrete.ECGroup; + +/** + * Created by Tzlil on 12/30/2015. + */ +public class ElGamalProofOrganizer { + + private final ECGroup group; + private final ECPoint g; + private final ECPoint h; + private final byte[] gEncoded; + private final byte[] hEncoded; + + public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){ + this.group = group; + this.g = g; + this.h = h; + this.gEncoded = group.encode(g); + this.hEncoded = group.encode(h); + } + + public enum OrProofOrder { + first, second, third, fourth + } + + public enum TrueCouple { + left, right, unknown + } + + //used by prover only + protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e2 + , Crypto.RerandomizableEncryptedMessage e1New, Crypto.RerandomizableEncryptedMessage e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException { + + //convert RerandomizableEncryptedMessage to ElGamalCiphertext + ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ConcreteCrypto.ElGamalCiphertext e1NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); + ConcreteCrypto.ElGamalCiphertext e2NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + + return new ElGamalProofInput(e1ElGamal,e2ElGamal,e1NewElGamal,e2NewElGamal,r1,r2,switched); + } + + // can be used by anyone, e.g Verifier + public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e2 + , Crypto.RerandomizableEncryptedMessage e1New, Crypto.RerandomizableEncryptedMessage e2New) throws InvalidProtocolBufferException { + + //convert RerandomizableEncryptedMessage to ElGamalCiphertext + ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ConcreteCrypto.ElGamalCiphertext e1NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); + ConcreteCrypto.ElGamalCiphertext e2NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + + return new ElGamalProofInput(e1ElGamal,e2ElGamal,e1NewElGamal,e2NewElGamal); + } + + + public class ElGamalProofInput { + + + private final OrProofInput first; + private final OrProofInput second; + private final OrProofInput third; + private final OrProofInput fourth; + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){ + + ECPoint e1c1 = convert2ECPoint(e1.getC1()); + ECPoint e1c2 = convert2ECPoint(e1.getC2()); + ECPoint e2c1 = convert2ECPoint(e2.getC1()); + ECPoint e2c2 = convert2ECPoint(e2.getC2()); + ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); + ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); + ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); + ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); + + ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); + ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); + ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); + ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); + + ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); + ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); + ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); + ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); + + byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); + byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); + byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); + byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); + byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); + byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); + byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); + byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); + + + if (!switched) { + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2 + ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e1NDive2Encoded,c2_e1NDive2Encoded + ,r1,TrueCouple.left); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1 + ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e2NDive1Encoded,c2_e2NDive1Encoded + ,r1,TrueCouple.left); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2 + ,c1_e1NDive2Encoded,c2_e1NDive2Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded + ,r2,TrueCouple.right); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2 + ,c1_e2NDive1Encoded,c2_e2NDive1Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded + ,r2,TrueCouple.right); + } else { + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2 + ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e1NDive2Encoded,c2_e1NDive2Encoded + ,r2,TrueCouple.right); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1 + ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e2NDive1Encoded,c2_e2NDive1Encoded + ,r1,TrueCouple.right); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2 + ,c1_e1NDive2Encoded,c2_e1NDive2Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded + ,r2,TrueCouple.left); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2 + ,c1_e2NDive1Encoded,c2_e2NDive1Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded + ,r1,TrueCouple.left); + } + + } + + + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ + + ECPoint e1c1 = convert2ECPoint(e1.getC1()); + ECPoint e1c2 = convert2ECPoint(e1.getC2()); + ECPoint e2c1 = convert2ECPoint(e2.getC1()); + ECPoint e2c2 = convert2ECPoint(e2.getC2()); + ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); + ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); + ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); + ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); + + ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); + ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); + ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); + ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); + + ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); + ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); + ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); + ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); + + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); + } + + + + public OrProofInput getOrProofInput(OrProofOrder orProofOrder) { + switch (orProofOrder) { + + case first: + return this.first; + case second: + return this.second; + case third: + return this.third; + case fourth: + return this.fourth; + } + return null; + } + } + public class OrProofInput{ + + public final ECPoint g1; + public final ECPoint h1; + public final ECPoint g2; + public final ECPoint h2; + public final ECPoint g1Tag; + public final ECPoint h1Tag; + public final ECPoint g2Tag; + public final ECPoint h2Tag; + + protected final byte[] g1Encoded; + protected final byte[] h1Encoded; + protected final byte[] g2Encoded; + protected final byte[] h2Encoded; + protected final byte[] g1TagEncoded; + protected final byte[] h1TagEncoded; + protected final byte[] g2TagEncoded; + protected final byte[] h2TagEncoded; + + protected final Crypto.EncryptionRandomness x; + protected final TrueCouple flag; + + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag + ,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded + , Crypto.EncryptionRandomness x, TrueCouple flag) { + this.g1 = g; + this.h1 = h1; + this.g2 = h; + this.h2 = h2; + this.g1Tag = g; + this.h1Tag = h1Tag; + this.g2Tag = h; + this.h2Tag = h2Tag; + + this.g1Encoded = gEncoded; + this.h1Encoded = h1Encoded; + this.g2Encoded = hEncoded; + this.h2Encoded = h2Encoded; + this.g1TagEncoded = gEncoded; + this.h1TagEncoded = h1TagEncoded; + this.g2TagEncoded = hEncoded; + this.h2TagEncoded = h2TagEncoded; + + this.x = x; + this.flag = flag; + + } + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) { + this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown); + } + } +} diff --git a/mixer/src/main/java/prover/ProofOrganizer.java b/mixer/src/main/java/prover/ProofOrganizer.java deleted file mode 100644 index 16b032b..0000000 --- a/mixer/src/main/java/prover/ProofOrganizer.java +++ /dev/null @@ -1,85 +0,0 @@ -package prover; - -import meerkat.protobuf.Crypto; - -/** - * Created by Tzlil on 12/30/2015. - */ -public class ProofOrganizer { - - private final OrProofInput first; - private final OrProofInput second; - private final OrProofInput third; - private final OrProofInput fourth; - - protected ProofOrganizer(Crypto.RerandomizableEncryptedMessage e1,Crypto.RerandomizableEncryptedMessage e2 - ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New - ,Crypto.EncryptionRandomness r1,Crypto.EncryptionRandomness r2,boolean switched) { - if(!switched) { - this.first = new OrProofInput(e1, e1New, e2, e1New, r1,TrueCouple.left); - this.second = new OrProofInput(e1, e1New, e1, e2New,r1,TrueCouple.left); - this.third = new OrProofInput(e2, e1New, e2, e2New,r2,TrueCouple.right); - this.fourth = new OrProofInput(e1, e2New, e2, e2New,r2,TrueCouple.right); - }else{ - this.first = new OrProofInput(e1, e1New, e2, e1New, r2,TrueCouple.right); - this.second = new OrProofInput(e1, e1New, e1, e2New,r1,TrueCouple.right); - this.third = new OrProofInput(e2, e1New, e2, e2New,r2,TrueCouple.left); - this.fourth = new OrProofInput(e1, e2New, e2, e2New,r1,TrueCouple.left); - } - - } - - public ProofOrganizer(Crypto.RerandomizableEncryptedMessage e1,Crypto.RerandomizableEncryptedMessage e2 - ,Crypto.RerandomizableEncryptedMessage e1New,Crypto.RerandomizableEncryptedMessage e2New) { - this.first = new OrProofInput(e1, e1New, e2, e1New, null,TrueCouple.unknown); - this.second = new OrProofInput(e1, e1New, e1, e2New,null,TrueCouple.unknown); - this.third = new OrProofInput(e2, e1New, e2, e2New,null,TrueCouple.unknown); - this.fourth = new OrProofInput(e1, e2New, e2, e2New,null,TrueCouple.unknown); - } - - public enum OrProofOrder{ - first,second,third,fourth - } - - public enum TrueCouple{ - left,right,unknown - } - - - public OrProofInput getOrProofInput(OrProofOrder orProofOrder){ - switch (orProofOrder){ - - case first: - return this.first; - case second: - return this.second; - case third: - return this.third; - case fourth: - return this.fourth; - } - return null; - } - - public class OrProofInput{ - - - public final Crypto.RerandomizableEncryptedMessage e1; - public final Crypto.RerandomizableEncryptedMessage e1New; - public final Crypto.RerandomizableEncryptedMessage e2; - public final Crypto.RerandomizableEncryptedMessage e2New; - protected final Crypto.EncryptionRandomness x; - protected final TrueCouple flag; - - private OrProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e1New, - Crypto.RerandomizableEncryptedMessage e2, Crypto.RerandomizableEncryptedMessage e2New, - Crypto.EncryptionRandomness x, TrueCouple flag) { - this.e1 = e1; - this.e1New = e1New; - this.e2 = e2; - this.e2New = e2New; - this.x = x; - this.flag = flag; - } - } -} diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 5cbd2c0..93c2536 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -4,8 +4,6 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -14,7 +12,6 @@ import qilin.primitives.RandomOracle; import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; -import java.util.List; import java.util.Random; public class Prover implements Mix2ZeroKnowledgeProver { @@ -24,6 +21,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { Random rand; ECElGamalEncryption ecElGamalEncryption; ECPoint g,h; + ElGamalProofOrganizer organizer; public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { @@ -33,10 +31,9 @@ public class Prover implements Mix2ZeroKnowledgeProver { this.group = ecElGamalEncryption.getGroup(); this.g = group.getGenerator(); this.h = ecElGamalEncryption.getElGamalPK().getPK(); + this.organizer = new ElGamalProofOrganizer(group,g,h); } - - public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, @@ -44,18 +41,14 @@ public class Prover implements Mix2ZeroKnowledgeProver { boolean sw,int i,int j, int layer, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { - Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; - ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2,r1,r2,sw); - System.out.println("first"); - first = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.first)); - System.out.println("second"); - second = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.second)); - System.out.println("third"); - third = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.third)); - System.out.println("fourth"); - fourth = createOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.fourth)); + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw); + + first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first)); + second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second)); + third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third)); + fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth)); Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() .setI(i) @@ -70,25 +63,9 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setFourth(fourth) .setLocation(location) .build(); - return result; } - private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ProofOrganizer.OrProofInput orProofInput) - throws InvalidProtocolBufferException { - - ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1); - ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2); - ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1New); - ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2New); - - return createOrProofElGamal(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProofInput.x,orProofInput.flag); - } - - - private ECPoint convert2ECPoint(ByteString bs){ - return group.decode(bs.toByteArray()); - } public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { byte[] arr = input.toByteArray(); @@ -96,28 +73,25 @@ public class Prover implements Mix2ZeroKnowledgeProver { } - private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalCiphertext e1, - ElGamalCiphertext e2, - ElGamalCiphertext e1New, - ElGamalCiphertext e2New, - Crypto.EncryptionRandomness x, - ProofOrganizer.TrueCouple flag) { + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) { - ECPoint g1 = g; - ECPoint h1 = group.add(convert2ECPoint(e1New.getC1()),group.negate(convert2ECPoint(e1.getC1()))); - ECPoint g2 = h; - ECPoint h2 = group.add(convert2ECPoint(e1New.getC2()),group.negate(convert2ECPoint(e1.getC2()))); + ECPoint g1 = orProofInput.g1; + ECPoint h1 = orProofInput.h1; + ECPoint g2 = orProofInput.g2; + ECPoint h2 = orProofInput.h2; - ECPoint g1Tag = g; - ECPoint h1Tag = group.add(convert2ECPoint(e2New.getC1()),group.negate(convert2ECPoint(e2.getC1()))); - ECPoint g2Tag = h; - ECPoint h2Tag = group.add(convert2ECPoint(e2New.getC2()),group.negate(convert2ECPoint(e2.getC2()))); + ECPoint g1Tag = orProofInput.g1Tag; + ECPoint h1Tag = orProofInput.h1Tag; + ECPoint g2Tag = orProofInput.g2Tag; + ECPoint h2Tag = orProofInput.h2Tag; BigInteger r = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); BigInteger c1,c2,z,zTag; ECPoint u,v,uTag,vTag; Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; - switch (flag) { + + + switch (orProofInput.flag) { case left: c2 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); zTag = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); @@ -130,14 +104,14 @@ public class Prover implements Mix2ZeroKnowledgeProver { // c1 = (hash(input + step1) + group size - c2)% group size forRandomOracle = Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(group.encode(g1))) - .setH1(ByteString.copyFrom(group.encode(h1))) - .setG2(ByteString.copyFrom(group.encode(g2))) - .setH2(ByteString.copyFrom(group.encode(h2))) - .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) - .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) - .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) - .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) .setU(ByteString.copyFrom(group.encode(u))) .setV(ByteString.copyFrom(group.encode(v))) .setUTag(ByteString.copyFrom(group.encode(uTag))) @@ -146,7 +120,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); //step 3 //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); + z = r.add(c1.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(group.orderUpperBound()); break; case right: c1 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); @@ -160,14 +134,14 @@ public class Prover implements Mix2ZeroKnowledgeProver { // c1 = (hash(input + step1) + group size - c1)% group size forRandomOracle = Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(group.encode(g1))) - .setH1(ByteString.copyFrom(group.encode(h1))) - .setG2(ByteString.copyFrom(group.encode(g2))) - .setH2(ByteString.copyFrom(group.encode(h2))) - .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) - .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) - .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) - .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) .setU(ByteString.copyFrom(group.encode(u))) .setV(ByteString.copyFrom(group.encode(v))) .setUTag(ByteString.copyFrom(group.encode(uTag))) @@ -176,39 +150,37 @@ public class Prover implements Mix2ZeroKnowledgeProver { c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); //step 3 //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(new BigInteger(x.getData().toByteArray()))).mod(group.orderUpperBound()); + zTag = r.add(c2.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(group.orderUpperBound()); break; default: return null; } //debugging - assert (group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1)))); - assert (group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1)))); - assert (group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2)))); - assert (group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2)))); + //assert (group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1)))); + //assert (group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1)))); + //assert (group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2)))); + //assert (group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2)))); return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() - .setG1(ByteString.copyFrom(group.encode(g1))) - .setH1(ByteString.copyFrom(group.encode(h1))) - .setG2(ByteString.copyFrom(group.encode(g2))) - .setH2(ByteString.copyFrom(group.encode(h2))) - .setG1Tag(ByteString.copyFrom(group.encode(g1Tag))) - .setH1Tag(ByteString.copyFrom(group.encode(h1Tag))) - .setG2Tag(ByteString.copyFrom(group.encode(g2Tag))) - .setH2Tag(ByteString.copyFrom(group.encode(h2Tag))) - .setU(ByteString.copyFrom(group.encode(u))) - .setV(ByteString.copyFrom(group.encode(v))) - .setUTag(ByteString.copyFrom(group.encode(uTag))) - .setVTag(ByteString.copyFrom(group.encode(vTag))) + .setG1(forRandomOracle.getG1()) + .setH1(forRandomOracle.getH1()) + .setG2(forRandomOracle.getG2()) + .setH2(forRandomOracle.getH2()) + .setG1Tag(forRandomOracle.getG1()) + .setH1Tag(forRandomOracle.getH1Tag()) + .setG2Tag(forRandomOracle.getG2Tag()) + .setH2Tag(forRandomOracle.getH2Tag()) + .setU(forRandomOracle.getU()) + .setV(forRandomOracle.getV()) + .setUTag(forRandomOracle.getUTag()) + .setVTag(forRandomOracle.getVTag()) .setC1(ByteString.copyFrom(c1.toByteArray())) .setC2(ByteString.copyFrom(c2.toByteArray())) .setZ(ByteString.copyFrom(z.toByteArray())) .setZTag(ByteString.copyFrom(zTag.toByteArray())) .build(); } - - } diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index 977abfc..efe77aa 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -8,7 +8,7 @@ import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; -import prover.ProofOrganizer; +import prover.ElGamalProofOrganizer; import qilin.primitives.RandomOracle; import qilin.primitives.concrete.ECGroup; @@ -33,6 +33,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { RandomOracle randomOracle; ECElGamalEncryption encryptor; ECPoint g,h; + ElGamalProofOrganizer organizer; public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { this.encryptor = encryptor; @@ -40,6 +41,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { this.g = group.getGenerator(); this.h = encryptor.getElGamalPK().getPK(); this.randomOracle = randomOracle; + this.organizer = new ElGamalProofOrganizer(group,g,h); } public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { @@ -57,26 +59,14 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { - - ProofOrganizer organizer = new ProofOrganizer(in1,in2,out1,out2); - return verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.first), proof.getFirst())&& - verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.second), proof.getSecond())&& - verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.third), proof.getThird())&& - verifyOrProof(organizer.getOrProofInput(ProofOrganizer.OrProofOrder.fourth), proof.getFourth()); + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2); + return verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first), proof.getFirst())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second), proof.getSecond())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third), proof.getThird())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth), proof.getFourth()); } - public boolean verifyOrProof(ProofOrganizer.OrProofInput orProofInput, Mixing.ZeroKnowledgeProof.OrProof orProof) - throws InvalidProtocolBufferException { - ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1); - ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2); - ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e1New); - ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(orProofInput.e2New); - return verifyElGamaOrProof(e1ElGamal,e2ElGamal,e1TagElGamal,e2TagElGamal,orProof); - } - - - private ECPoint g1,g2,h1,h2; private ECPoint g1Tag,g2Tag,h1Tag,h2Tag; private ECPoint u,v,uTag,vTag; @@ -117,23 +107,16 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { zTag = new BigInteger(orProof.getZTag().toByteArray()); } - private List createConditionsList(ElGamalCiphertext e1, - ElGamalCiphertext e2, - ElGamalCiphertext e1New, - ElGamalCiphertext e2New){ + private List createConditionsList(ElGamalProofOrganizer.OrProofInput orProofInput){ List conditions = new ArrayList(); - conditions.add(new Condition( g1,g,"g1 != g")); - conditions.add(new Condition( h1,group.add(convert2ECPoint(e1New.getC1()), - group.negate(convert2ECPoint(e1.getC1()))),"h1 != e1New.c1/e1.c1")); - conditions.add(new Condition( g2,h,"g2 != h")); - conditions.add(new Condition( h2,group.add(convert2ECPoint(e1New.getC2()), - group.negate(convert2ECPoint(e1.getC2()))),"h2 != e1New.c2/e1.c2")); - conditions.add(new Condition( g1Tag,g,"g1Tag != g")); - conditions.add(new Condition( h1Tag,group.add(convert2ECPoint(e2New.getC1()), - group.negate(convert2ECPoint(e2.getC1()))),"h1Tag != e2New.c1/e2.c1")); - conditions.add(new Condition( g2Tag,h,"g2Tag != h")); - conditions.add(new Condition( h2Tag,group.add(convert2ECPoint(e2New.getC2()), - group.negate(convert2ECPoint(e2.getC2()))),"h2Tag != e2New.c2/e2.c2")); + conditions.add(new Condition( g1,orProofInput.g1,"g1 != g")); + conditions.add(new Condition( h1,orProofInput.h1,"h1 != e1New.c1/e1.c1")); + conditions.add(new Condition( g2,orProofInput.g2,"g2 != h")); + conditions.add(new Condition( h2,orProofInput.h2,"h2 != e1New.c2/e1.c2")); + conditions.add(new Condition( g1Tag,orProofInput.g1Tag,"g1Tag != g")); + conditions.add(new Condition( h1Tag,orProofInput.h1Tag,"h1Tag != e2New.c1/e2.c1")); + conditions.add(new Condition( g2Tag,orProofInput.g2,"g2Tag != h")); + conditions.add(new Condition( h2Tag,orProofInput.h2,"h2Tag != e2New.c2/e2.c2")); conditions.add(new Condition(c1.add(c2).mod(group.orderUpperBound()), hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()), "(c1 + c2 ) % group size == hash (imput + step1) % group size")); @@ -148,14 +131,11 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { return conditions; } - public boolean verifyElGamaOrProof(ElGamalCiphertext e1, - ElGamalCiphertext e2, - ElGamalCiphertext e1New, - ElGamalCiphertext e2New, - Mixing.ZeroKnowledgeProof.OrProof orProof) + public boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, Mixing.ZeroKnowledgeProof.OrProof orProof) + { parseOrProof(orProof); - List conditions = createConditionsList(e1,e2,e1New,e2New); + List conditions = createConditionsList(orProofInput); boolean result = true; for (Condition condition: conditions) { diff --git a/mixer/src/main/java/verifier/VerifyTable.java b/mixer/src/main/java/verifier/VerifyTable.java index a0075c0..37fdedb 100644 --- a/mixer/src/main/java/verifier/VerifyTable.java +++ b/mixer/src/main/java/verifier/VerifyTable.java @@ -2,6 +2,7 @@ package verifier; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import qilin.util.Pair; @@ -13,8 +14,8 @@ import java.util.Arrays; */ public final class VerifyTable { - public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,Pair mixerOutput) throws InvalidProtocolBufferException { + public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput) + throws InvalidProtocolBufferException { int index1,index2,layer; //assert n = 2^k @@ -29,8 +30,8 @@ public final class VerifyTable { Arrays.fill(locationChecksumLayer,false); } - Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.a; - Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.b; + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.gerProofs(); + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { diff --git a/mixer/src/test/java/mixer/CreateTestVector.java b/mixer/src/test/java/mixer/CreateTestVector.java new file mode 100644 index 0000000..fcb273b --- /dev/null +++ b/mixer/src/test/java/mixer/CreateTestVector.java @@ -0,0 +1,100 @@ +package mixer; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import verifier.Verifier; +import verifier.VerifyTable; + +import java.io.IOException; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 1/19/2016. + */ +public class CreateTestVector { + + + ECElGamalEncryption encryptor; + ECGroup group; + Random random,randomMixer,randomProver; + RandomOracle randomOracle; + Mix2ZeroKnowledgeVerifier verifier; + Mix2ZeroKnowledgeProver prover; + meerkat.crypto.mixnet.Mixer mixer; + private int layers; + private int n; + + + @Before + public void setup() throws InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + encryptor = new ECElGamalEncryption(); + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + randomMixer = new Random(); + randomProver = new Random(); + randomOracle = new DigestOracle(); + verifier = new Verifier(encryptor,randomOracle); + prover = new Prover(randomProver,encryptor,randomOracle); + mixer = new Mixer(randomMixer,prover,encryptor,verifier); + + // generate n + int logN = 10; // + random.nextInt(8) + layers = 2*logN - 1; + n = 1 << logN; + } + + public List generateMixerInput(){ + List result = new ArrayList(); + Voting.PlaintextBallot msg; + for (int i = 0; i < n ; i++){ + msg = Utiles.genRandomBallot(2,3,16); + result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); + } + return result; + } + //@Test + public void createValidTest() throws IOException { + + List mixerInput = generateMixerInput(); + System.out.println("start mixing"); + MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + System.out.println("mixing ended, start verification"); + assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); + System.out.println("verification ended, start printing"); + mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); + System.out.println("all done"); + } + + //@Test + public void createInvalidTest() throws IOException { + + //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(encryptor,randomOracle,true); + //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,encryptor,randomOracle,true); + //mixer = new Mixer(randomMixer,corruptedProver,encryptor,corruptedVerifier); + + List mixerInput = generateMixerInput(); + System.out.println("start mixing"); + MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + System.out.println("mixing ended, start negative verification"); + assert (!VerifyTable.verifyTable(verifier,n,mixerOutput)); + System.out.println("verification ended, start printing"); + mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); + System.out.println("all done"); + } +} diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index ac05513..23645ed 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -6,8 +6,7 @@ package mixer; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.*; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import meerkat.protobuf.Voting; @@ -33,7 +32,7 @@ public class MixingText { Random random,randomMixer,randomProver; RandomOracle randomOracle; Mix2ZeroKnowledgeVerifier verifier; - Mix2ZeroKnowledgeProver prover; + Prover prover; meerkat.crypto.mixnet.Mixer mixer; private int layers; private int n; @@ -54,7 +53,7 @@ public class MixingText { mixer = new Mixer(randomMixer,prover,encryptor); // generate n - int logN = 8; // + random.nextInt(8) + int logN = 10; // + random.nextInt(8) layers = 2*logN - 1; n = 1 << logN; } @@ -71,7 +70,23 @@ public class MixingText { @Test public void mixingTest() throws InvalidProtocolBufferException { - Pair mixerOutput = mixer.mix(generateMixerInput()); + System.out.println("n is : " + n); + System.out.println(" generating input"); + List mixerInput = generateMixerInput(); + System.out.println(" start mixing"); + long startTime = System.currentTimeMillis(); + + meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput); + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + + System.out.println("start verification"); + startTime = System.currentTimeMillis(); + assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); + + finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); } } diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index 6e29bb5..f98bc1e 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -67,8 +67,8 @@ public class RerandomizeTest { ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(eNew); assert (g.multiply(new BigInteger(r.getData().toByteArray())).equals( - group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))))); - assert (h.multiply(new BigInteger(r.getData().toByteArray())).equals( + group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))))); + assert(h.multiply(new BigInteger(r.getData().toByteArray())).equals( group.add(convert2ECPoint(eNewElGamal.getC2()), group.negate(convert2ECPoint(eElGamal.getC2()))))); } diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java b/mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java new file mode 100644 index 0000000..3c9880f --- /dev/null +++ b/mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java @@ -0,0 +1,65 @@ +package profiling.ECGroupProfiling; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 1/20/2016. + */ +public class AddProfiling { + + ECElGamalEncryption encryptor; + ECGroup group; + Random random; + private int n; + List members1; + List members2; + + @Before + public void setup() throws InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + encryptor = new ECElGamalEncryption(); + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + // generate n; + int sqrtn = 128; + n = sqrtn*sqrtn; + + members1 = new ArrayList(sqrtn); + members2 = new ArrayList(sqrtn); + + for (int i = 0 ; i < sqrtn; i ++){ + members1.add(group.sample(random)); + members2.add(group.sample(random)); + } + } + + @Test + public void addProfiling() throws InvalidProtocolBufferException { + System.out.println("Add"); + System.out.println("n is : " + n); + System.out.println("start n operations"); + long startTime = System.currentTimeMillis(); + for (ECPoint member1: members1) { + for (ECPoint member2: members2) { + group.add(member1,member2); + } + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + } +} diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java b/mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java new file mode 100644 index 0000000..af03f70 --- /dev/null +++ b/mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java @@ -0,0 +1,59 @@ +package profiling.ECGroupProfiling; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 1/20/2016. + */ +public class EncodeProfiling { + + ECElGamalEncryption encryptor; + ECGroup group; + Random random; + private int n; + List members; + + @Before + public void setup() throws InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + encryptor = new ECElGamalEncryption(); + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + // generate n; + int sqrtn = 128; + n = sqrtn*sqrtn; + + members = new ArrayList(n); + for (int i = 0 ; i < n; i ++){ + members.add(group.sample(random)); + } + } + @Test + public void encodeProfiling() throws InvalidProtocolBufferException { + System.out.println("Encode"); + System.out.println("n is : " + n); + + System.out.println("start n operations"); + long startTime = System.currentTimeMillis(); + for (ECPoint member: members) { + group.encode(member); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + } +} diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java b/mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java new file mode 100644 index 0000000..bb7c7cb --- /dev/null +++ b/mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java @@ -0,0 +1,81 @@ +package profiling.ECGroupProfiling; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import mixer.Mixer; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import verifier.Verifier; +import verifier.VerifyTable; + +import java.math.BigInteger; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 1/19/2016. + */ +public class MulProfiling { + + ECElGamalEncryption encryptor; + ECGroup group; + Random random; + private int n; + List members; + List randomnesses; + @Before + public void setup() throws InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + encryptor = new ECElGamalEncryption(); + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + // generate n + int sqrtn = 128; + n = sqrtn*sqrtn; + + members = new ArrayList(sqrtn); + randomnesses = new ArrayList(sqrtn); + + byte[] arr = new byte[256]; + for (int i = 0 ; i < sqrtn; i ++){ + members.add(group.sample(random)); + random.nextBytes(arr); + randomnesses.add(new BigInteger(arr)); + } + } + + @Test + public void mulProfiling() throws InvalidProtocolBufferException { + System.out.println("Multiply"); + System.out.println("n is : " + n); + + System.out.println("start n operations"); + long startTime = System.currentTimeMillis(); + for(ECPoint member:members) { + for (BigInteger rand : randomnesses) { + group.multiply(member, rand); + + } + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n*n)+ " ms"); + } + + + +} diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java b/mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java new file mode 100644 index 0000000..344a813 --- /dev/null +++ b/mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java @@ -0,0 +1,59 @@ +package profiling.ECGroupProfiling; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by Tzlil on 1/20/2016. + */ +public class NegateProfiling { + + ECElGamalEncryption encryptor; + ECGroup group; + Random random; + private int n; + List members; + + @Before + public void setup() throws InvalidKeySpecException { + // initialization + random = new Random(); + group = new ECGroup("secp256k1"); + encryptor = new ECElGamalEncryption(); + encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + // generate n; + int sqrtn = 128; + n = sqrtn*sqrtn; + + members = new ArrayList(n); + for (int i = 0 ; i < n; i ++){ + members.add(group.sample(random)); + } + } + @Test + public void negProfiling() throws InvalidProtocolBufferException { + System.out.println("Neg"); + System.out.println("n is : " + n); + + System.out.println("start n operations"); + long startTime = System.currentTimeMillis(); + for (ECPoint member: members) { + group.negate(member); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + } +} diff --git a/mixer/src/test/java/profiling/RerandomizeProfiling.java b/mixer/src/test/java/profiling/RerandomizeProfiling.java new file mode 100644 index 0000000..01148ec --- /dev/null +++ b/mixer/src/test/java/profiling/RerandomizeProfiling.java @@ -0,0 +1,79 @@ +package profiling; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/20/2016. + */ +public class RerandomizeProfiling { + + Random rand; + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + int n; + Crypto.EncryptionRandomness[] randomnesses; + Crypto.RerandomizableEncryptedMessage[] encryptedMessage; + + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + n = 1024 * 18; + randomnesses = new Crypto.EncryptionRandomness[n]; + encryptedMessage = new Crypto.RerandomizableEncryptedMessage[n]; + + Voting.PlaintextBallot msg; + + for (int i = 0; i < n ; i ++){ + msg = Utiles.genRandomBallot(2,3,16); + randomnesses[i] = enc.generateRandomness(rand); + encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); + } + } + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + @Test + public void RerandomizeProfiling() throws InvalidProtocolBufferException { + + System.out.println("Rerandomiz"); + System.out.println("n is : " + n); + System.out.println("start n operations"); + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < n ; i ++){ + enc.rerandomize(encryptedMessage[i],randomnesses[i]); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/n + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProofProfiling.java b/mixer/src/test/java/profiling/ZeroKnowledgeProofProfiling.java new file mode 100644 index 0000000..ec91ddb --- /dev/null +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProofProfiling.java @@ -0,0 +1,87 @@ +package profiling; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/20/2016. + */ +public class ZeroKnowledgeProofProfiling { + + Random rand; + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + Mix2ZeroKnowledgeProver prover ; + int n; + Crypto.EncryptionRandomness[] randomnesses; + Crypto.RerandomizableEncryptedMessage[] encryptedMessage; + Crypto.RerandomizableEncryptedMessage[] reencryptedMessage; + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + RandomOracle randomOracle = new DigestOracle(); + prover = new Prover(new Random(),enc,randomOracle); + n = 512 * 18; + randomnesses = new Crypto.EncryptionRandomness[n*2]; + encryptedMessage = new Crypto.RerandomizableEncryptedMessage[n*2]; + reencryptedMessage = new Crypto.RerandomizableEncryptedMessage[n*2]; + + Voting.PlaintextBallot msg; + + for (int i = 0; i < n*2 ; i ++){ + msg = Utiles.genRandomBallot(2,3,16); + randomnesses[i] = enc.generateRandomness(rand); + encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); + reencryptedMessage[i] = enc.rerandomize(encryptedMessage[i], randomnesses[i]); + } + } + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + @Test + public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException { + + System.out.println("Prove"); + System.out.println("n is : " + n); + System.out.println("start n proves"); + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < n*2 ; i +=2){ + prover.prove(encryptedMessage[i],encryptedMessage[i+1],reencryptedMessage[i],reencryptedMessage[i+1], + false,0,0,0,randomnesses[i],randomnesses[i+1]); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/n + " ms"); + } +} From efde36d869f901df457546b64e49e0a351a8e0f6 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Mon, 25 Jan 2016 16:48:36 +0200 Subject: [PATCH 15/66] profiling --- .../crypto/concrete/ECDSASignature.java | 2 +- .../crypto/concrete/ECElGamalEncryption.java | 2 +- mixer/src/main/java/main/BatchConverter.java | 14 +- mixer/src/main/java/main/BatchHandler.java | 5 +- mixer/src/main/java/main/MainMixing.java | 78 +++-- mixer/src/main/java/mixer/Mixer.java | 127 +++++--- .../java/prover/ElGamalProofOrganizer.java | 278 +++++++++++------- mixer/src/main/java/prover/Prover.java | 93 ++++-- mixer/src/main/java/verifier/Verifier.java | 141 +++------ .../verifier/ZeroKnowledgeOrProofParser.java | 69 +++++ .../src/test/java/mixer/RerandomizeTest.java | 8 +- .../java/mixer/ZeroKnowledgeProofTest.java | 8 +- .../java/profiling/BigInteger/AddSub.java | 69 +++++ .../BigInteger/GenerateRandomness.java | 49 +++ .../java/profiling/BigInteger/Modulo.java | 57 ++++ .../test/java/profiling/BigInteger/Mul.java | 63 ++++ .../java/profiling/BigInteger/SHA256.java | 57 ++++ .../profiling/Convert/ByteString2ECPoint.java | 73 +++++ ...bleEncryptedMessage2ElGamalCiphertext.java | 67 +++++ .../AddProfiling.java => ECGroup/Add.java} | 8 +- .../Encode.java} | 6 +- .../MulProfiling.java => ECGroup/Mul.java} | 15 +- .../Negate.java} | 6 +- ...ndomizeProfiling.java => Rerandomize.java} | 10 +- ...Profiling.java => ZeroKnowledgeProof.java} | 7 +- 25 files changed, 936 insertions(+), 376 deletions(-) create mode 100644 mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java create mode 100644 mixer/src/test/java/profiling/BigInteger/AddSub.java create mode 100644 mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java create mode 100644 mixer/src/test/java/profiling/BigInteger/Modulo.java create mode 100644 mixer/src/test/java/profiling/BigInteger/Mul.java create mode 100644 mixer/src/test/java/profiling/BigInteger/SHA256.java create mode 100644 mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java create mode 100644 mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java rename mixer/src/test/java/profiling/{ECGroupProfiling/AddProfiling.java => ECGroup/Add.java} (93%) rename mixer/src/test/java/profiling/{ECGroupProfiling/EncodeProfiling.java => ECGroup/Encode.java} (94%) rename mixer/src/test/java/profiling/{ECGroupProfiling/MulProfiling.java => ECGroup/Mul.java} (83%) rename mixer/src/test/java/profiling/{ECGroupProfiling/NegateProfiling.java => ECGroup/Negate.java} (94%) rename mixer/src/test/java/profiling/{RerandomizeProfiling.java => Rerandomize.java} (93%) rename mixer/src/test/java/profiling/{ZeroKnowledgeProofProfiling.java => ZeroKnowledgeProof.java} (95%) diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 6cbcf8d..b0a79f2 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -44,7 +44,7 @@ public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignatur ByteBuffer lenBuf = ByteBuffer.allocate(4); - Map loadedCertificates = new HashMap<>(); + Map loadedCertificates = new HashMap(); /** * Signature currently loaded (will be used in calls to {@link #verify()}). diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 910a1aa..5dae4b7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -109,7 +109,7 @@ public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption .build(); } - public static ConcreteCrypto.ElGamalCiphertext rerandomizableEncryptedMessage2ElGamalCiphertext(Crypto.RerandomizableEncryptedMessage msg) throws InvalidProtocolBufferException { + public static ConcreteCrypto.ElGamalCiphertext RerandomizableEncryptedMessage2ElGamalCiphertext(Crypto.RerandomizableEncryptedMessage msg) throws InvalidProtocolBufferException { return ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); } diff --git a/mixer/src/main/java/main/BatchConverter.java b/mixer/src/main/java/main/BatchConverter.java index 008c868..919f406 100644 --- a/mixer/src/main/java/main/BatchConverter.java +++ b/mixer/src/main/java/main/BatchConverter.java @@ -5,7 +5,6 @@ import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import qilin.util.Pair; import java.math.BigInteger; import java.util.ArrayList; @@ -22,7 +21,8 @@ public class BatchConverter { this.n = n; this.layers = layers; } - private ByteString IntegerToByteString(int a){ + + private ByteString Integer2ByteString(int a){ return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); } @@ -30,12 +30,12 @@ public class BatchConverter { return Integer.valueOf(bs.toString()); } - public List mixerOutput2BatchData(MixerOutput mixerOutput) { + public List MixerOutput2BatchData(MixerOutput mixerOutput) { List result = new ArrayList(); result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(IntegerToByteString(n)) + .setData(Integer2ByteString(n)) .build()); for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.gerProofs()) { @@ -55,7 +55,7 @@ public class BatchConverter { return result; } - public MixerOutput batchDataList2MixerOutput + public MixerOutput BatchDataList2MixerOutput (List batchDataList) throws Exception { if (n != ByteString2Integer(batchDataList.remove(0).getData())){ @@ -64,7 +64,7 @@ public class BatchConverter { int nDiv2 = n >>1; Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; - for (int layer = 0; layer mixerInput; - - if (mixerOrder > 0) { - List batchHandlers = new ArrayList(prevBatchIds.size()); - BatchHandler currentBatchHandler; - for (Integer prevBatchId : prevBatchIds) { - currentBatchHandler = new BatchHandler(n, layers,verifier); - asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); - batchHandlers.add(currentBatchHandler); - } - - // ToDo : assert table continues - // ToDo : assert signature validity - - boolean allDone = false; - while (!allDone) { - try { - Thread.sleep(30); - } catch (InterruptedException e) { - // do nothing - } - // check all handlers messages were received - allDone = true; - for (BatchHandler batchHandler : batchHandlers) { - allDone &= batchHandler.isMsgReceived(); - } - } - - // assert all handlers succeeded - for (BatchHandler batchHandler : batchHandlers) { - if(!batchHandler.verifyTable()){ - throw new Exception("invalid input"); - } - } - - BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); - mixerInput = lastBatchHandler.getInputForMixer(); - - } else { - // ToDo : handle first mixer case - mixerInput = null; + List batchHandlers = new ArrayList(prevBatchIds.size()); + BatchHandler currentBatchHandler; + for (Integer prevBatchId : prevBatchIds) { + currentBatchHandler = new BatchHandler(n, layers,verifier); + asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); + batchHandlers.add(currentBatchHandler); } + // ToDo : assert table continues + // ToDo : assert signature validity + + boolean allDone = false; + while (!allDone) { + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing + } + // check all handlers messages were received + allDone = true; + for (BatchHandler batchHandler : batchHandlers) { + allDone &= batchHandler.isMsgReceived(); + } + } + + // assert all handlers succeeded + for (BatchHandler batchHandler : batchHandlers) { + if(!batchHandler.verifyTable()){ + throw new Exception("invalid input"); + } + } + + BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); + mixerInput = lastBatchHandler.getInputForMixer(); + MixerOutput mixerOutput = mixer.mix(mixerInput); updateBB(mixerOutput, batchId, callback); @@ -95,7 +85,7 @@ public class MainMixing { , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { BatchConverter batchConverter = new BatchConverter(n,layers); - List batchDataList = batchConverter.mixerOutput2BatchData(mixerOutput); + List batchDataList = batchConverter.MixerOutput2BatchData(mixerOutput); asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); } diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 51a7950..477e740 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -22,10 +22,10 @@ import verifier.Verifier; public class Mixer implements meerkat.crypto.mixnet.Mixer { - private Random random; - private Mix2ZeroKnowledgeProver prover; - private Encryption encryptor; - private Mix2ZeroKnowledgeVerifier verifier; + protected final Random random; + protected final Mix2ZeroKnowledgeProver prover; + protected final Encryption encryptor; + protected final Mix2ZeroKnowledgeVerifier verifier; public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc) { this.random = rand; @@ -41,45 +41,51 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { this.verifier = verifier; } - public MixerOutput mix(List ciphertexts) throws InvalidProtocolBufferException { - - int n = ciphertexts.size(); - int nDiv2 = n >> 1; - // assert n = 2^k and n > 1 - if (n <= 1 || ((n & (n - 1)) != 0)) - return null; - - //initialization - int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 - RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; - ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][n]; - int index1, index2, switchIndex = 0; - EncryptionRandomness r1, r2; - RerandomizableEncryptedMessage e1, e2; - boolean half = true; - MixNetwork mixNetwork = new MixNetwork(new RandomPermutation(n,random)); - Switch[] switchesLayer; - - EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; + // assert n = 2^k and n > 1 + protected boolean inputBasicCheckSum(int n){ + return n > 1 && ((n & (n - 1)) == 0); + } + protected RerandomizableEncryptedMessage[][] initializeEncryptionTable(int n,int layers,List ciphertexts){ // set first level of encryption - for (int j = 0; j < n; j++) { - encryptionTable[0][j] = ciphertexts.get(j); - } + RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; + for (int j = 0; j < n; j++) { + encryptionTable[0][j] = ciphertexts.get(j); + } + return encryptionTable; + } + protected EncryptionRandomness[][] generateRandomnessesForRerandomize(int n,int layers){ + EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; + for (int layer = 0; layer < layers; layer++) + { + for (int i = 0; i < n; i++) { + randomnesses[layer][i] = encryptor.generateRandomness(random);; + } + } + return randomnesses; + } - BigInteger time = BigInteger.valueOf(System.currentTimeMillis()); - // main loop - for (int layer = 0; layer < layers; layer++) - { - switchesLayer = mixNetwork.getSwitchesByLayer(layer); - for (Switch sw : switchesLayer) { - index1 = sw.i; - index2 = sw.j; - e1 = encryptionTable[layer][index1]; - e2 = encryptionTable[layer][index2]; + protected MixNetwork createMixNetwork(int n){ + return new MixNetwork(new RandomPermutation(n,random)); + } - r1 = encryptor.generateRandomness(random); - r2 = encryptor.generateRandomness(random); + protected void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable + ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + Switch[] switchesLayer; + int index1,index2; + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; if (!sw.value) { encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); @@ -88,13 +94,19 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); } - randomnesses[layer][index1] = r1; - randomnesses[layer][index2] = r2; - } - } - System.out.println("re enc time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); - time = BigInteger.valueOf(System.currentTimeMillis()); - // main loop + } + } + } + + protected ZeroKnowledgeProof[][] createZKPTable(int n,int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable + ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][n]; + Switch[] switchesLayer; + int index1,index2; + int switchIndex = 0; + int nDiv2 = n >> 1; + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; for (int layer = 0; layer < layers; layer++) { switchesLayer = mixNetwork.getSwitchesByLayer(layer); @@ -114,7 +126,30 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { switchIndex = (switchIndex + 1) % nDiv2; } } + return proofsTable; + } + + public MixerOutput mix(List ciphertexts) throws InvalidProtocolBufferException { + + int n = ciphertexts.size(); + int nDiv2 = n >> 1; + + if (!inputBasicCheckSum(n)) + return null; + + int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 + RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts); + EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers); + MixNetwork mixNetwork = createMixNetwork(n); + + BigInteger time = BigInteger.valueOf(System.currentTimeMillis()); + rerandomize(layers,mixNetwork,encryptionTable,randomnesses); + System.out.println("re enc time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); + + time = BigInteger.valueOf(System.currentTimeMillis()); + ZeroKnowledgeProof[][] proofsTable = createZKPTable(n,layers,mixNetwork,encryptionTable,randomnesses); System.out.println("zkp time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); + return new mixer.MixerOutput(n,layers,proofsTable, encryptionTable); } diff --git a/mixer/src/main/java/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/prover/ElGamalProofOrganizer.java index cec8256..540e944 100644 --- a/mixer/src/main/java/prover/ElGamalProofOrganizer.java +++ b/mixer/src/main/java/prover/ElGamalProofOrganizer.java @@ -9,7 +9,9 @@ import org.bouncycastle.math.ec.ECPoint; import qilin.primitives.concrete.ECGroup; /** - * Created by Tzlil on 12/30/2015. + * use for organize the input for each ZKP + * + * both prover and verifier implantation are using it */ public class ElGamalProofOrganizer { @@ -19,6 +21,11 @@ public class ElGamalProofOrganizer { private final byte[] gEncoded; private final byte[] hEncoded; + /** + * @param group + * @param g - generator of group + * @param h - h = g ^ SecretKey + */ public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){ this.group = group; this.g = g; @@ -35,37 +42,68 @@ public class ElGamalProofOrganizer { left, right, unknown } - //used by prover only - protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e2 - , Crypto.RerandomizableEncryptedMessage e1New, Crypto.RerandomizableEncryptedMessage e2New + /** + * can be used by prover only + * + * call to the main overload with flag = true + */ + protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException { - //convert RerandomizableEncryptedMessage to ElGamalCiphertext - ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); - ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); - ConcreteCrypto.ElGamalCiphertext e1NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); - ConcreteCrypto.ElGamalCiphertext e2NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); - - return new ElGamalProofInput(e1ElGamal,e2ElGamal,e1NewElGamal,e2NewElGamal,r1,r2,switched); + //boolean flag = true; + return createProofInput(in1,in2,out1,out2,r1,r2,switched,true); } - // can be used by anyone, e.g Verifier - public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage e1, Crypto.RerandomizableEncryptedMessage e2 - , Crypto.RerandomizableEncryptedMessage e1New, Crypto.RerandomizableEncryptedMessage e2New) throws InvalidProtocolBufferException { + /** + * can be used by anyone, e.g verifier + * + * call to the main overload with flag = false + */ + public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException { + + // flag = false; + return createProofInput(in1,in2,out1,out2,null,null,false,false); + } + + /** + * inner method + * convert each encrypted message to ElGamalCiphertext + * + * @param flag - true if called by prover ( r1,r2,switched are known) + * @return ElGamalProofInput + * @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't + * ElGamalCiphertext + */ + private ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag) + throws InvalidProtocolBufferException { //convert RerandomizableEncryptedMessage to ElGamalCiphertext - ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); - ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); - ConcreteCrypto.ElGamalCiphertext e1NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); - ConcreteCrypto.ElGamalCiphertext e2NewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1); + ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2); + ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1); + ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2); - return new ElGamalProofInput(e1ElGamal,e2ElGamal,e1NewElGamal,e2NewElGamal); + if(flag) { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched); + }else { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal); + } } + /** + * can be construct by instance of organizer only by calling createProofInput method (all constructors are private) + * + * in construction it use for preparing the input for prove, while avoiding double converting or calculations + * + * use as a container for 4 OrProofInput. + */ public class ElGamalProofInput { - private final OrProofInput first; private final OrProofInput second; private final OrProofInput third; @@ -75,100 +113,111 @@ public class ElGamalProofOrganizer { return group.decode(bs.toByteArray()); } + + /** + * @param flag - true if called by prover ( r1,r2,switched are known) + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag){ + + ECPoint e1c1 = convert2ECPoint(e1.getC1()); + ECPoint e1c2 = convert2ECPoint(e1.getC2()); + ECPoint e2c1 = convert2ECPoint(e2.getC1()); + ECPoint e2c2 = convert2ECPoint(e2.getC2()); + ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); + ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); + ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); + ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); + + ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); + ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); + ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); + ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); + + ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); + ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); + ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); + ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); + + + if(!flag){ + + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); + + }else { + + byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); + byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); + byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); + byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); + byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); + byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); + byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); + byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); + + + if (!switched) { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r1, TrueCouple.left); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.left); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + } else { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r2, TrueCouple.right); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.right); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.left); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r1, TrueCouple.left); + } + } + } + + + /** + * used by the prover + * call to the main constructor with flag = true + */ private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){ - - ECPoint e1c1 = convert2ECPoint(e1.getC1()); - ECPoint e1c2 = convert2ECPoint(e1.getC2()); - ECPoint e2c1 = convert2ECPoint(e2.getC1()); - ECPoint e2c2 = convert2ECPoint(e2.getC2()); - ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); - ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); - ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); - ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); - - ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); - ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); - ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); - ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); - - ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); - ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); - ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); - ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); - - byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); - byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); - byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); - byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); - byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); - byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); - byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); - byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); - - - if (!switched) { - this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2 - ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e1NDive2Encoded,c2_e1NDive2Encoded - ,r1,TrueCouple.left); - this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1 - ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e2NDive1Encoded,c2_e2NDive1Encoded - ,r1,TrueCouple.left); - this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2 - ,c1_e1NDive2Encoded,c2_e1NDive2Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded - ,r2,TrueCouple.right); - this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2 - ,c1_e2NDive1Encoded,c2_e2NDive1Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded - ,r2,TrueCouple.right); - } else { - this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2 - ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e1NDive2Encoded,c2_e1NDive2Encoded - ,r2,TrueCouple.right); - this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1 - ,c1_e1NDive1Encoded,c2_e1NDive1Encoded,c1_e2NDive1Encoded,c2_e2NDive1Encoded - ,r1,TrueCouple.right); - this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2 - ,c1_e1NDive2Encoded,c2_e1NDive2Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded - ,r2,TrueCouple.left); - this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2 - ,c1_e2NDive1Encoded,c2_e2NDive1Encoded,c1_e2NDive2Encoded,c2_e2NDive2Encoded - ,r1,TrueCouple.left); - } - + //flag = true; + this(e1,e2,e1New,e2New,r1,r2,switched,true); } - + /** + * used by prover + * call to the main constructor with flag = true + */ private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ - - ECPoint e1c1 = convert2ECPoint(e1.getC1()); - ECPoint e1c2 = convert2ECPoint(e1.getC2()); - ECPoint e2c1 = convert2ECPoint(e2.getC1()); - ECPoint e2c2 = convert2ECPoint(e2.getC2()); - ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); - ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); - ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); - ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); - - ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); - ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); - ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); - ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); - - ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); - ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); - ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); - ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); - - this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); - this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); - this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); - this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); + //flag = false; + this(e1,e2,e1New,e2New,null,null,false,false); } - - + /** + * getter for all 4 OrProofInputs + * + * @param orProofOrder + * @return the required OrProof + */ public OrProofInput getOrProofInput(OrProofOrder orProofOrder) { switch (orProofOrder) { @@ -184,8 +233,16 @@ public class ElGamalProofOrganizer { return null; } } - public class OrProofInput{ + + /** + * can't be constructed (all constructors are private) + * + * 4 instances will be constructed for each new ElGamalProofInput + * + * container for all necessary inputs for single OrProof + */ + public class OrProofInput{ public final ECPoint g1; public final ECPoint h1; public final ECPoint g2; @@ -195,6 +252,7 @@ public class ElGamalProofOrganizer { public final ECPoint g2Tag; public final ECPoint h2Tag; + // can be access by prover only protected final byte[] g1Encoded; protected final byte[] h1Encoded; protected final byte[] g2Encoded; @@ -203,10 +261,12 @@ public class ElGamalProofOrganizer { protected final byte[] h1TagEncoded; protected final byte[] g2TagEncoded; protected final byte[] h2TagEncoded; - protected final Crypto.EncryptionRandomness x; protected final TrueCouple flag; + /** + * used by prover only + */ private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag ,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded , Crypto.EncryptionRandomness x, TrueCouple flag) { @@ -232,6 +292,10 @@ public class ElGamalProofOrganizer { this.flag = flag; } + + /** + * use by verifier + */ private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) { this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown); } diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 93c2536..93fba71 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -4,7 +4,6 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; @@ -14,26 +13,52 @@ import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; + +/** + * implements of Mix2ZeroKnowledgeProver interface + * this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext + */ public class Prover implements Mix2ZeroKnowledgeProver { - ECGroup group; - RandomOracle randomOracle; - Random rand; - ECElGamalEncryption ecElGamalEncryption; - ECPoint g,h; - ElGamalProofOrganizer organizer; + private final ECGroup group; + private final RandomOracle randomOracle; + private final Random rand; + private final ECElGamalEncryption encryptor; + private final ECPoint g,h; + private final BigInteger groupOrderUpperBound; + private final ElGamalProofOrganizer organizer; + /** + * @param rand + * @param encryptor + * @param randomOracle - use for Fiat–Shamir heuristic + */ public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { this.rand = rand; - this.ecElGamalEncryption = encryptor; + this.encryptor = encryptor; this.randomOracle = randomOracle; - this.group = ecElGamalEncryption.getGroup(); + this.group = this.encryptor.getGroup(); this.g = group.getGenerator(); - this.h = ecElGamalEncryption.getElGamalPK().getPK(); + this.h = this.encryptor.getElGamalPK().getPK(); this.organizer = new ElGamalProofOrganizer(group,g,h); + this.groupOrderUpperBound = group.orderUpperBound(); } + /** + * @param in1 + * @param in2 + * @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1) + * @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2) + * @param sw - flag + * @param i - column of in1 and out1 in encryption table + * @param j - column of in2 and out2 in encryption table + * @param layer - row of in1,in2 in encryption table + * @param r1 + * @param r2 + * @return - a valid ZKP that indeed out1,out2 calculated as required + * @throws InvalidProtocolBufferException + */ public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, @@ -67,12 +92,22 @@ public class Prover implements Mix2ZeroKnowledgeProver { } - public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { + /** + * Fiat–Shamir heuristic + * @param input - protobuf contains all parameters from the first step of the current prove + * @return randomOracle.hash(input) + */ + private BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { byte[] arr = input.toByteArray(); return new BigInteger(this.randomOracle.hash(arr,arr.length)); } + /** + * @param orProofInput + * @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2) + * assuming DLog is hard in this.group then that proves x is known for the prover + */ private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) { ECPoint g1 = orProofInput.g1; @@ -85,7 +120,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { ECPoint g2Tag = orProofInput.g2Tag; ECPoint h2Tag = orProofInput.h2Tag; - BigInteger r = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); BigInteger c1,c2,z,zTag; ECPoint u,v,uTag,vTag; Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; @@ -93,8 +128,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { switch (orProofInput.flag) { case left: - c2 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - zTag = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); + zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); //step 1 u = group.multiply(g1, r); v = group.multiply(g2, r); @@ -109,22 +144,22 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setG2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) .setU(ByteString.copyFrom(group.encode(u))) .setV(ByteString.copyFrom(group.encode(v))) .setUTag(ByteString.copyFrom(group.encode(uTag))) .setVTag(ByteString.copyFrom(group.encode(vTag))) .build(); - c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(group.orderUpperBound()); + c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); //step 3 //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(group.orderUpperBound()); + z = r.add(c1.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(groupOrderUpperBound); break; case right: - c1 = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); - z = new BigInteger(ecElGamalEncryption.generateRandomness(rand).getData().toByteArray()).mod(group.orderUpperBound()); + c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); + z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); //step 1 uTag = group.multiply(g1Tag, r); vTag = group.multiply(g2Tag, r); @@ -139,29 +174,23 @@ public class Prover implements Mix2ZeroKnowledgeProver { .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setG2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH2Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) .setU(ByteString.copyFrom(group.encode(u))) .setV(ByteString.copyFrom(group.encode(v))) .setUTag(ByteString.copyFrom(group.encode(uTag))) .setVTag(ByteString.copyFrom(group.encode(vTag))) .build(); - c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(group.orderUpperBound()); + c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); //step 3 //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(group.orderUpperBound()); + zTag = r.add(c2.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(groupOrderUpperBound); break; default: return null; } - //debugging - //assert (group.multiply(g1, z).equals(group.add(u, group.multiply(h1,c1)))); - //assert (group.multiply(g2, z).equals(group.add(v, group.multiply(h2,c1)))); - //assert (group.multiply(g1Tag, zTag).equals(group.add(uTag, group.multiply(h1Tag,c2)))); - //assert (group.multiply(g2Tag, zTag).equals(group.add(vTag, group.multiply(h2Tag,c2)))); - return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() .setG1(forRandomOracle.getG1()) diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index efe77aa..94c6084 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -1,10 +1,8 @@ package verifier; -import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; @@ -20,20 +18,12 @@ import java.util.List; public class Verifier implements Mix2ZeroKnowledgeVerifier { - /** - * Return true iff the proof is valid. - * @param in1 - * @param in2 - * @param out1 - * @param out2 - * @return - */ - - ECGroup group; - RandomOracle randomOracle; - ECElGamalEncryption encryptor; - ECPoint g,h; - ElGamalProofOrganizer organizer; + private final ECGroup group; + private final RandomOracle randomOracle; + private final ECElGamalEncryption encryptor; + private final ECPoint g,h; + private final ElGamalProofOrganizer organizer; + private final ZeroKnowledgeOrProofParser parser; public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { this.encryptor = encryptor; @@ -42,18 +32,16 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { this.h = encryptor.getElGamalPK().getPK(); this.randomOracle = randomOracle; this.organizer = new ElGamalProofOrganizer(group,g,h); + this.parser = new ZeroKnowledgeOrProofParser(group); } public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { byte[] arr = input.toByteArray(); return new BigInteger(this.randomOracle.hash(arr,arr.length)); } - - private ECPoint convert2ECPoint(ByteString bs){ - return group.decode(bs.toByteArray()); - } - - + /** + * @return true iff the proof is valid + */ public boolean verify(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, @@ -67,97 +55,62 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { } - private ECPoint g1,g2,h1,h2; - private ECPoint g1Tag,g2Tag,h1Tag,h2Tag; - private ECPoint u,v,uTag,vTag; - private BigInteger c1,c2,z,zTag; - private Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; - private void parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ - forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(orProof.getG1()) - .setH1(orProof.getH1()) - .setG2(orProof.getG2()) - .setH2(orProof.getH2()) - .setG1Tag(orProof.getG1Tag()) - .setH1Tag(orProof.getH1Tag()) - .setG2Tag(orProof.getG2Tag()) - .setH2Tag(orProof.getH2Tag()) - .setU(orProof.getU()) - .setV(orProof.getV()) - .setUTag(orProof.getUTag()) - .setVTag(orProof.getVTag()) - .build(); - g1 = convert2ECPoint(orProof.getG1()); - g2 = convert2ECPoint(orProof.getG2()); - h1 = convert2ECPoint(orProof.getH1()); - h2 = convert2ECPoint(orProof.getH2()); - g1Tag = convert2ECPoint(orProof.getG1Tag()); - g2Tag = convert2ECPoint(orProof.getG2Tag()); - h1Tag = convert2ECPoint(orProof.getH1Tag()); - h2Tag = convert2ECPoint(orProof.getH2Tag()); - u = convert2ECPoint(orProof.getU()); - v = convert2ECPoint(orProof.getV()); - uTag = convert2ECPoint(orProof.getUTag()); - vTag = convert2ECPoint(orProof.getVTag()); - c1 = new BigInteger(orProof.getC1().toByteArray()); - c2 = new BigInteger(orProof.getC2().toByteArray()); - z = new BigInteger(orProof.getZ().toByteArray()); - zTag = new BigInteger(orProof.getZTag().toByteArray()); - } - private List createConditionsList(ElGamalProofOrganizer.OrProofInput orProofInput){ - List conditions = new ArrayList(); - conditions.add(new Condition( g1,orProofInput.g1,"g1 != g")); - conditions.add(new Condition( h1,orProofInput.h1,"h1 != e1New.c1/e1.c1")); - conditions.add(new Condition( g2,orProofInput.g2,"g2 != h")); - conditions.add(new Condition( h2,orProofInput.h2,"h2 != e1New.c2/e1.c2")); - conditions.add(new Condition( g1Tag,orProofInput.g1Tag,"g1Tag != g")); - conditions.add(new Condition( h1Tag,orProofInput.h1Tag,"h1Tag != e2New.c1/e2.c1")); - conditions.add(new Condition( g2Tag,orProofInput.g2,"g2Tag != h")); - conditions.add(new Condition( h2Tag,orProofInput.h2,"h2Tag != e2New.c2/e2.c2")); - conditions.add(new Condition(c1.add(c2).mod(group.orderUpperBound()), - hash(forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()), - "(c1 + c2 ) % group size == hash (imput + step1) % group size")); - conditions.add(new Condition( group.multiply(g1, z), - group.add(u, group.multiply(h1,c1)),"g1 ^ z != u * ( h1 ^ c1 )")); - conditions.add(new Condition( group.multiply(g2, z), - group.add(v, group.multiply(h2,c1)),"g2 ^ z != v * ( h2 ^ c1 )")); - conditions.add(new Condition( group.multiply(g1Tag, zTag), - group.add(uTag, group.multiply(h1Tag,c2)),"g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )")); - conditions.add(new Condition( group.multiply(g2Tag, zTag), - group.add(vTag, group.multiply(h2Tag,c2)),"g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )")); - return conditions; - } - - public boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, Mixing.ZeroKnowledgeProof.OrProof orProof) - - { - parseOrProof(orProof); - List conditions = createConditionsList(orProofInput); + public boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, + Mixing.ZeroKnowledgeProof.OrProof orProof) { + ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof); + List conditions = createConditionsList(orProofInput,container); boolean result = true; - for (Condition condition: conditions) { + for (Condition condition: conditions) { //temporary if(!condition.test()){ if (result){ result = false; System.out.print("\n\n\n"); } - System.out.println(condition.errorDescripton); + System.out.println(condition.errorDescription); } } return result; } + + private List createConditionsList(ElGamalProofOrganizer.OrProofInput orProofInput + ,ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container){ + List conditions = new ArrayList(); + conditions.add(new Condition( container.g1,orProofInput.g1,"g1 != g")); + conditions.add(new Condition( container.h1,orProofInput.h1,"h1 != e1New.c1/e1.c1")); + conditions.add(new Condition( container.g2,orProofInput.g2,"g2 != h")); + conditions.add(new Condition( container.h2,orProofInput.h2,"h2 != e1New.c2/e1.c2")); + conditions.add(new Condition( container.g1Tag,orProofInput.g1Tag,"g1Tag != g")); + conditions.add(new Condition( container.h1Tag,orProofInput.h1Tag,"h1Tag != e2New.c1/e2.c1")); + conditions.add(new Condition( container.g2Tag,orProofInput.g2Tag,"g2Tag != h")); + conditions.add(new Condition( container.h2Tag,orProofInput.h2Tag,"h2Tag != e2New.c2/e2.c2")); + conditions.add(new Condition(container.c1.add(container.c2).mod(group.orderUpperBound()), + hash(container.forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()), + "(c1 + c2 ) % group size == hash (imput + step1) % group size")); + conditions.add(new Condition( group.multiply(container.g1, container.z), + group.add(container.u, group.multiply(container.h1,container.c1)),"g1 ^ z != u * ( h1 ^ c1 )")); + conditions.add(new Condition( group.multiply(container.g2, container.z), + group.add(container.v, group.multiply(container.h2,container.c1)),"g2 ^ z != v * ( h2 ^ c1 )")); + conditions.add(new Condition( group.multiply(container.g1Tag, container.zTag), + group.add(container.uTag, group.multiply(container.h1Tag,container.c2)) + ,"g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )")); + conditions.add(new Condition( group.multiply(container.g2Tag, container.zTag), + group.add(container.vTag, group.multiply(container.h2Tag,container.c2)) + ,"g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )")); + return conditions; + } + private class Condition{ T given, expected; - String errorDescripton; + String errorDescription; - Condition(T given,T expected,String descripton){ + Condition(T given,T expected,String description){ this.given = given; - this.errorDescripton = descripton; + this.errorDescription = description; this.expected = expected; } diff --git a/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java new file mode 100644 index 0000000..d3f82a5 --- /dev/null +++ b/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java @@ -0,0 +1,69 @@ +package verifier; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class ZeroKnowledgeOrProofParser { + + private final ECGroup group; + public ZeroKnowledgeOrProofParser(ECGroup group) { + this.group = group; + } + + public ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ + return new ZeroKnowledgeOrProofContainer(orProof); + } + + public class ZeroKnowledgeOrProofContainer{ + public final ECPoint g1,g2,h1,h2; + public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; + public final ECPoint u,v,uTag,vTag; + public final BigInteger c1,c2,z,zTag; + public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ + this.forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(orProof.getG1()) + .setH1(orProof.getH1()) + .setG2(orProof.getG2()) + .setH2(orProof.getH2()) + .setG1Tag(orProof.getG1Tag()) + .setH1Tag(orProof.getH1Tag()) + .setG2Tag(orProof.getG2Tag()) + .setH2Tag(orProof.getH2Tag()) + .setU(orProof.getU()) + .setV(orProof.getV()) + .setUTag(orProof.getUTag()) + .setVTag(orProof.getVTag()) + .build(); + this.g1 = convert2ECPoint(orProof.getG1()); + this.g2 = convert2ECPoint(orProof.getG2()); + this.h1 = convert2ECPoint(orProof.getH1()); + this.h2 = convert2ECPoint(orProof.getH2()); + this.g1Tag = convert2ECPoint(orProof.getG1Tag()); + this.g2Tag = convert2ECPoint(orProof.getG2Tag()); + this.h1Tag = convert2ECPoint(orProof.getH1Tag()); + this.h2Tag = convert2ECPoint(orProof.getH2Tag()); + this.u = convert2ECPoint(orProof.getU()); + this.v = convert2ECPoint(orProof.getV()); + this.uTag = convert2ECPoint(orProof.getUTag()); + this.vTag = convert2ECPoint(orProof.getVTag()); + this.c1 = new BigInteger(orProof.getC1().toByteArray()); + this.c2 = new BigInteger(orProof.getC2().toByteArray()); + this.z = new BigInteger(orProof.getZ().toByteArray()); + this.zTag = new BigInteger(orProof.getZTag().toByteArray()); + } + } +} diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index f98bc1e..c607f61 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -3,20 +3,16 @@ package mixer; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.bouncycastle.math.ec.ECPoint; import org.junit.Before; import org.junit.Test; -import prover.Prover; import qilin.primitives.RandomOracle; import qilin.primitives.concrete.DigestOracle; import qilin.primitives.concrete.ECElGamal; import qilin.primitives.concrete.ECGroup; -import verifier.Verifier; import java.math.BigInteger; import java.util.Random; @@ -63,8 +59,8 @@ public class RerandomizeTest { assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg)); assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg)); - ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e); - ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(eNew); + ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e); + ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew); assert (g.multiply(new BigInteger(r.getData().toByteArray())).equals( group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))))); diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index a0952e2..5bfedc8 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -70,10 +70,10 @@ public class ZeroKnowledgeProofTest { ECPoint g = group.getGenerator(); ECPoint h = enc.getElGamalPK().getPK(); - ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1); - ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2); - ConcreteCrypto.ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e1New); - ConcreteCrypto.ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.rerandomizableEncryptedMessage2ElGamalCiphertext(e2New); + ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e1); + ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e2); + ConcreteCrypto.ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e1New); + ConcreteCrypto.ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e2New); assert (g.multiply(new BigInteger(r1.getData().toByteArray())).equals( diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java new file mode 100644 index 0000000..1505aca --- /dev/null +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -0,0 +1,69 @@ +package profiling.BigInteger; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/21/2016. + */ +public class AddSub { + + int tests; + BigInteger[] randoms; + BigInteger[] randoms2; + + @Before + public void setup() throws Exception { + Random rand = new Random(); + tests = 1 << 17; + randoms = new BigInteger[tests]; + rand = new Random(); + + ECGroup group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + ECElGamal.SK key = new ECElGamal.SK(group, sk); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ECElGamalEncryption enc = new ECElGamalEncryption(); + enc.init(serializedPk); + + for (int i =0 ; i < tests ; i++){ + randoms[i] = new BigInteger(enc.generateRandomness(rand).getData().toByteArray()); + } + randoms2 = new BigInteger[tests]; + for (int i =0 ; i < tests ; i++){ + randoms2[i] = new BigInteger(enc.generateRandomness(rand).getData().toByteArray()); + } + + } + + @Test + public void AddSubProfiling() throws InvalidProtocolBufferException { + + System.out.println("AddSub"); + System.out.println("#" + tests + " tests"); + long startTime = System.currentTimeMillis(); + int i = 0; + while (i < randoms.length / 2) { + randoms[i].add(randoms2[i]); + i++; + } + while (i < randoms.length) { + randoms[i].subtract(randoms2[i]); + i++; + } + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java new file mode 100644 index 0000000..837fcc5 --- /dev/null +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -0,0 +1,49 @@ +package profiling.BigInteger; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import mixer.Utiles; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class GenerateRandomness { + int tests; + ECElGamalEncryption enc; + Random rand; + @Before + public void setup() throws Exception { + rand = new Random(); + ECGroup group = new ECGroup("secp256k1"); + tests = 1<<18; + + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + ECElGamal.SK key = new ECElGamal.SK(group, sk); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + + } + + @Test + public void GenerateRandomnessProfiling() throws InvalidProtocolBufferException { + + System.out.println("GenerateRandomnessProfiling"); + System.out.println("#" + tests + " tests"); + long startTime = System.currentTimeMillis(); + for (int i =0 ; i < tests ; i++){ + enc.generateRandomness(rand).getData().toByteArray(); + } + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java new file mode 100644 index 0000000..a1757ee --- /dev/null +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -0,0 +1,57 @@ +package profiling.BigInteger; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/21/2016. + */ +public class Modulo { + int tests; + BigInteger[] randoms; + BigInteger orderUpperBound; + + @Before + public void setup() throws Exception { + Random rand = new Random(); + ECGroup group = new ECGroup("secp256k1"); + orderUpperBound = group.orderUpperBound(); + tests = 1<<17; + randoms = new BigInteger[tests]; + + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + ECElGamal.SK key = new ECElGamal.SK(group, sk); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ECElGamalEncryption enc = new ECElGamalEncryption(); + enc.init(serializedPk); + for (int i =0 ; i < tests ; i++){ + randoms[i] = new BigInteger(enc.generateRandomness(rand).getData().toByteArray()); + } + } + + @Test + public void ModuloProfiling() throws InvalidProtocolBufferException { + + System.out.println("ModuloProfiling"); + System.out.println("#" + tests + " tests"); + long startTime = System.currentTimeMillis(); + for (int i = 0 ; i < randoms.length;i++) { + randoms[i].mod(orderUpperBound); + } + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java new file mode 100644 index 0000000..9656255 --- /dev/null +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -0,0 +1,63 @@ +package profiling.BigInteger; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import mixer.Utiles; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class Mul { + + int tests; + BigInteger[] randoms; + BigInteger[] randoms2; + + @Before + public void setup() throws Exception { + Random rand = new Random(); + tests = 1 << 17; + randoms = new BigInteger[tests]; + rand = new Random(); + + ECGroup group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + ECElGamal.SK key = new ECElGamal.SK(group, sk); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ECElGamalEncryption enc = new ECElGamalEncryption(); + enc.init(serializedPk); + + for (int i =0 ; i < tests ; i++){ + randoms[i] = new BigInteger(enc.generateRandomness(rand).getData().toByteArray()); + } + randoms2 = new BigInteger[tests]; + for (int i =0 ; i < tests ; i++){ + randoms2[i] = new BigInteger(enc.generateRandomness(rand).getData().toByteArray()); + } + + } + + @Test + public void MulProfiling() throws InvalidProtocolBufferException { + + System.out.println("Mul"); + System.out.println("#" + tests + " tests"); + long startTime = System.currentTimeMillis(); + int i = 0; + while (i < randoms.length) { + randoms[i].multiply(randoms2[i]); + i++; + } + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/BigInteger/SHA256.java b/mixer/src/test/java/profiling/BigInteger/SHA256.java new file mode 100644 index 0000000..7e086a4 --- /dev/null +++ b/mixer/src/test/java/profiling/BigInteger/SHA256.java @@ -0,0 +1,57 @@ +package profiling.BigInteger; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class SHA256 { + final int LENGTH = 420; + int tests; + BigInteger[] randoms; + RandomOracle randomOracle; + + @Before + public void setup() throws Exception { + Random rand = new Random(); + randomOracle = new DigestOracle(); + tests = 1<<15; + Voting.PlaintextBallot msg; + randoms = new BigInteger[tests]; + byte[] arr = new byte[LENGTH]; + for (int i =0 ; i < tests ; i++){ + rand.nextBytes(arr); + randoms[i] = new BigInteger(arr); + } + } + + @Test + public void SHA256Profiling() throws InvalidProtocolBufferException { + + System.out.println("SHA256Profiling"); + System.out.println("#" + tests + " tests"); + long startTime = System.currentTimeMillis(); + for (int i = 0 ; i < randoms.length;i++) { + byte[] arr = randoms[i].toByteArray(); + new BigInteger(this.randomOracle.hash(arr, arr.length)); + } + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java new file mode 100644 index 0000000..77d1a68 --- /dev/null +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -0,0 +1,73 @@ +package profiling.Convert; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class ByteString2ECPoint { + Random rand; + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + int tests; + ConcreteCrypto.ElGamalCiphertext[] encryptedMessage; + + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + tests = 1024 * 19; + encryptedMessage = new ConcreteCrypto.ElGamalCiphertext[tests]; + + Voting.PlaintextBallot msg; + + for (int i = 0; i < tests; i ++){ + msg = Utiles.genRandomBallot(2,3,16); + + encryptedMessage[i] = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext + (enc.encrypt(msg, enc.generateRandomness(rand))); + } + } + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + @Test + public void ByteString2ECPointProfiling() throws InvalidProtocolBufferException { + + System.out.println("ByteString2ECPointProfiling"); + System.out.println("#"+ tests + " tests"); + System.out.println("start tests operations"); + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < tests; i ++){ + convert2ECPoint(encryptedMessage[i].getC1()); + convert2ECPoint(encryptedMessage[i].getC2()); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/ (2 * tests) + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java new file mode 100644 index 0000000..8639911 --- /dev/null +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -0,0 +1,67 @@ +package profiling.Convert; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import mixer.Utiles; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/25/2016. + */ +public class RerandomizableEncryptedMessage2ElGamalCiphertext { + Random rand; + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + int tests; + Crypto.RerandomizableEncryptedMessage[] encryptedMessage; + + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utiles.serializePk(group, key); + enc = new ECElGamalEncryption(); + enc.init(serializedPk); + tests = 1024 * 18; + encryptedMessage = new Crypto.RerandomizableEncryptedMessage[tests]; + + Voting.PlaintextBallot msg; + + for (int i = 0; i < tests; i ++){ + msg = Utiles.genRandomBallot(2,3,16); + + encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); + } + } + @Test + public void RerandomizableEncryptedMessage2ElGamalCiphertext() throws InvalidProtocolBufferException { + + System.out.println("RerandomizableEncryptedMessage2ElGamalCiphertext"); + System.out.println("#"+ tests + " tests"); + System.out.println("start tests operations"); + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < tests; i ++){ + ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(encryptedMessage[i]); + } + + long finishTime = System.currentTimeMillis(); + System.out.println(" that took: "+(finishTime-startTime)+ " ms"); + System.out.println(" avg of "+((double)(finishTime-startTime))/ tests + " ms"); + } +} diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java b/mixer/src/test/java/profiling/ECGroup/Add.java similarity index 93% rename from mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java rename to mixer/src/test/java/profiling/ECGroup/Add.java index 3c9880f..31865b9 100644 --- a/mixer/src/test/java/profiling/ECGroupProfiling/AddProfiling.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -1,4 +1,4 @@ -package profiling.ECGroupProfiling; +package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; @@ -17,7 +17,7 @@ import java.util.Random; /** * Created by Tzlil on 1/20/2016. */ -public class AddProfiling { +public class Add { ECElGamalEncryption encryptor; ECGroup group; @@ -48,7 +48,7 @@ public class AddProfiling { @Test public void addProfiling() throws InvalidProtocolBufferException { - System.out.println("Add"); + System.out.println("AddSub"); System.out.println("n is : " + n); System.out.println("start n operations"); long startTime = System.currentTimeMillis(); @@ -60,6 +60,6 @@ public class AddProfiling { long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); - System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n)+ " ms"); } } diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java b/mixer/src/test/java/profiling/ECGroup/Encode.java similarity index 94% rename from mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java rename to mixer/src/test/java/profiling/ECGroup/Encode.java index af03f70..a7a731f 100644 --- a/mixer/src/test/java/profiling/ECGroupProfiling/EncodeProfiling.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -1,4 +1,4 @@ -package profiling.ECGroupProfiling; +package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; @@ -17,7 +17,7 @@ import java.util.Random; /** * Created by Tzlil on 1/20/2016. */ -public class EncodeProfiling { +public class Encode { ECElGamalEncryption encryptor; ECGroup group; @@ -54,6 +54,6 @@ public class EncodeProfiling { long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); - System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n)+ " ms"); } } diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java b/mixer/src/test/java/profiling/ECGroup/Mul.java similarity index 83% rename from mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java rename to mixer/src/test/java/profiling/ECGroup/Mul.java index bb7c7cb..b0c0c7e 100644 --- a/mixer/src/test/java/profiling/ECGroupProfiling/MulProfiling.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -1,22 +1,13 @@ -package profiling.ECGroupProfiling; +package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Voting; -import mixer.Mixer; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; import org.junit.Before; import org.junit.Test; -import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; import qilin.primitives.concrete.ECElGamal; import qilin.primitives.concrete.ECGroup; -import verifier.Verifier; -import verifier.VerifyTable; import java.math.BigInteger; import java.security.spec.InvalidKeySpecException; @@ -27,7 +18,7 @@ import java.util.Random; /** * Created by Tzlil on 1/19/2016. */ -public class MulProfiling { +public class Mul { ECElGamalEncryption encryptor; ECGroup group; @@ -73,7 +64,7 @@ public class MulProfiling { long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); - System.out.println(" avg of"+((double)(finishTime-startTime))/(n*n)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n)+ " ms"); } diff --git a/mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java b/mixer/src/test/java/profiling/ECGroup/Negate.java similarity index 94% rename from mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java rename to mixer/src/test/java/profiling/ECGroup/Negate.java index 344a813..75030fa 100644 --- a/mixer/src/test/java/profiling/ECGroupProfiling/NegateProfiling.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -1,4 +1,4 @@ -package profiling.ECGroupProfiling; +package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; @@ -17,7 +17,7 @@ import java.util.Random; /** * Created by Tzlil on 1/20/2016. */ -public class NegateProfiling { +public class Negate { ECElGamalEncryption encryptor; ECGroup group; @@ -54,6 +54,6 @@ public class NegateProfiling { long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); - System.out.println(" avg of"+((double)(finishTime-startTime))/(n * n)+ " ms"); + System.out.println(" avg of"+((double)(finishTime-startTime))/(n)+ " ms"); } } diff --git a/mixer/src/test/java/profiling/RerandomizeProfiling.java b/mixer/src/test/java/profiling/Rerandomize.java similarity index 93% rename from mixer/src/test/java/profiling/RerandomizeProfiling.java rename to mixer/src/test/java/profiling/Rerandomize.java index 01148ec..ed018f3 100644 --- a/mixer/src/test/java/profiling/RerandomizeProfiling.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -23,7 +23,7 @@ import java.util.Random; /** * Created by Tzlil on 1/20/2016. */ -public class RerandomizeProfiling { +public class Rerandomize { Random rand; ECElGamal.SK key; @@ -43,7 +43,9 @@ public class RerandomizeProfiling { serializedPk = Utiles.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); - n = 1024 * 18; + int LogVotes = 10; + int layers = 2*LogVotes - 1; + n = layers * (1< Date: Tue, 23 Feb 2016 16:58:35 +0200 Subject: [PATCH 16/66] First version of Voter Booth Summary: Planned some basic interfaces for my revised Voting Booth componenets. No implementation yet, though... Test Plan: There are none, yet Reviewers: arbel.peled Differential Revision: https://proj-cs.idc.ac.il/D2 --- .../src/main/proto/meerkat/voting.proto | 37 +++++++-- .../meerkat/voting/BallotOutputDevice.java | 19 +++++ .../main/java/meerkat/voting/Encryptor.java | 13 +++ .../java/meerkat/voting/StorageManager.java | 12 +++ .../voting/SystemConsoleOutputDevice.java | 56 +++++++++++++ .../src/main/java/meerkat/voting/UI.java | 32 ++++++++ .../main/java/meerkat/voting/VotingBooth.java | 82 +++++++++++++++++++ 7 files changed, 245 insertions(+), 6 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/Encryptor.java create mode 100644 voting-booth/src/main/java/meerkat/voting/StorageManager.java create mode 100644 voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/UI.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBooth.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 9837cce..759a708 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -6,13 +6,38 @@ import 'meerkat/crypto.proto'; option java_package = "meerkat.protobuf"; -// A ballot question. This is an opaque -// data type that is parsed by the UI to display -// the question. -message BallotQuestion { - bytes data = 1; + + +// Type of the element data to be presented by UI +enum UIElementDataType { + TEXT = 0; + IMAGE = 1; + VOICE = 2; } +// Type of question +enum QuestionType { + MULTIPLE_CHOICE = 0; + MULTIPLE_SELECTION = 1; + ORDER = 2; +} + +// An element to be presented by UI +message UIElement { + UIElementDataType type = 1; + bytes data = 2; +} + +// a new data structure for BallotQuestion. Need to delete the old one +message BallotQuestion { + bool is_mandatory = 1; + UIElement question = 2; + UIElement description = 3; + repeated UIElement answer = 4; +} + + + // An answer to a specific ballot question. // The answer is a vector of signed integers, // to encompass voting schemes such as ranked voting @@ -83,7 +108,7 @@ message ElectionParams { repeated BallotQuestion questions = 6; // Translation table between answers and plaintext encoding - BallotAnswerTranslationTable answerTranslationTable = 7; + //BallotAnswerTranslationTable answerTranslationTable = 7; // Data required in order to access the Bulletin Board Servers BulletinBoardClientParams bulletinBoardClientParams = 8; diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java new file mode 100644 index 0000000..32e3208 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -0,0 +1,19 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 15/02/16. + */ +public interface BallotOutputDevice { + + void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback); + + void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback); + + void castBallot(long sessionId, VotingBooth.Callback callback); + + // probably has no difference than cast. Maybe drop this method + void cancelBallot(long sessionId, VotingBooth.Callback callback); + +} diff --git a/voting-booth/src/main/java/meerkat/voting/Encryptor.java b/voting-booth/src/main/java/meerkat/voting/Encryptor.java new file mode 100644 index 0000000..4cfcf57 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/Encryptor.java @@ -0,0 +1,13 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface Encryptor { + + public void encrypt (long sessionId, PlaintextBallot plaintextBallot); + + //TODO: probably needs some key generation methods as well +} diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java new file mode 100644 index 0000000..3edff7a --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -0,0 +1,12 @@ +package meerkat.voting; + +/** + * Created by hai on 23/02/16. + */ +public interface StorageManager { + + // should these methods be synchronous or asynchronous? Can we rely on it being immediate? + public void detectAdminHardwareKey(); + + public void readElectionParams (); +} diff --git a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java new file mode 100644 index 0000000..7546d53 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java @@ -0,0 +1,56 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 15/02/16. + */ +public class SystemConsoleOutputDevice implements BallotOutputDevice { + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + + @Override + public void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback) { + + System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " + + bytesToString(encryptedBallot.getData().getData())); + + callback.ballotCommitResult(sessionId, true); + + } + + @Override + public void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback) { + + //TODO: generate standard form for this + System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " + + bytesToString(encryptedBallot.getData().getData())); + + callback.ballotAuditResult(sessionId, true); + + } + + @Override + public void castBallot(long sessionId, VotingBooth.Callback callback) { + + System.out.println("Ballot finalized!"); + + callback.ballotCastResult(sessionId, true); + + } + + @Override + public void cancelBallot(long sessionId, VotingBooth.Callback callback) { + + System.out.println("Ballot cancelled!"); + + callback.ballotCancelResult(sessionId, true); + + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/UI.java b/voting-booth/src/main/java/meerkat/voting/UI.java new file mode 100644 index 0000000..83739db --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/UI.java @@ -0,0 +1,32 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface UI { + + + // Voter scenario methods + void introductionToVoter (long sessionId); + + void chooseChannel (long sessionId, BallotQuestion question); + + void askVoterQuestion (long sessionId, int questionNumber, BallotQuestion question); + + void castOrAudit (long sessionId); + + void showWaitForFinishScreen (long sessionId); + + + // Admin scenario methods + //TODO: the admin scenario still needs some more thinking + + + + // bad thing happened scenario + void showErrorMessageAndHalt (String errorMessage); + void showErrorMessageWithCancelButton (long sessionId, String errorMessage); + +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java new file mode 100644 index 0000000..a7df483 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -0,0 +1,82 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface VotingBooth { + + public enum ErrorID { + OUTPUT_DEVICE_OUT_OF_PAPER, + OUTPUT_DEVICE_OUT_OF_INK, + OUTPUT_DEVICE_NO_CONNECTION, + OUTPUT_DEVICE_HARDWARE_NOT_FOUND, + + UI_HARDWARE_NOT_FOUND + } + + + // keeps track in which state we are + // internal state will also include the number of the current question and the answers we got so far, + // later it includes the details of the PlaintextBallot and later the Encryption and the secrets + public enum State { + INITIALIZED, + + VOTER_INTRODUCTION, + VOTER_CHOOSE_CHANNEL, + VOTER_VOTING, + VOTER_ENCRYPTING, + VOTER_CAST_OR_AUDIT, + VOTER_CASTING, + VOTER_AUDITING + + } + + public interface Callback { + + // callbacks and messages from BallotOutputDevice + + public void ballotCommitResult (long sessionId, boolean result); + public void ballotCastResult (long sessionId, boolean result); + public void ballotAuditResult (long sessionId, boolean result); + public void ballotCancelResult (long sessionId, boolean result); + // other error messages, such as Printer turned-off or out-of-paper + public void outputDeviceReportProblem (ErrorID errorId); + + + // callbacks and messages from UI + + public void introductionFinished (long sessionId); + public void choiceOfChannel (long sessionId, int channelNumber); + public void skipQuestion (long sessionId, int questionNumber); + public void backwardsQuestion (long sessionId, int questionNumber); + public void cancelVotingSession (long sessionId); + public void answer (long sessionId, int questionNumber, String answer); + public void cast (long sessionId); + public void audit (long sessionId); + // other error messages, such as hardware-not-detected + public void uiReportProblem (ErrorID errorId); + + + // callbacks from encryptor + + public void returnEncryption (long sessionId, EncryptedBallot encryptedBallot, BallotSecrets secrets); + + + // callbacks from StorageManager + + public void adminHardwareKeyDetected (boolean isKeyInserted); + public void loadElectionParams (ElectionParams electionParams); + } + + // this function is synchronous + public void start (); + + + // messages from Admin Console (If there is such one) + // this function is asynchronous + public void shutDown(); + +} From 15453a772d4e23d4ab6718caafbd2eae28e4882e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 2 Mar 2016 19:52:17 +0200 Subject: [PATCH 17/66] Changes made in the initial interfaces for further code review. 1. Especially tried to fix the callback mechanism I previously used. 2. 'long sessionID' changed to 'int requestId' 3. Introduced a generic class VotingBoothResult 4. Quite some other local changes --- .../src/main/proto/meerkat/voting.proto | 4 +- .../meerkat/voting/BallotOutputDevice.java | 18 +++-- .../java/meerkat/voting/StorageManager.java | 7 +- .../src/main/java/meerkat/voting/UI.java | 32 --------- .../main/java/meerkat/voting/VotingBooth.java | 71 +++---------------- ...cryptor.java => VotingBoothEncryptor.java} | 4 +- .../meerkat/voting/VotingBoothResult.java | 17 +++++ .../java/meerkat/voting/VotingBoothUI.java | 64 +++++++++++++++++ 8 files changed, 111 insertions(+), 106 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/UI.java rename voting-booth/src/main/java/meerkat/voting/{Encryptor.java => VotingBoothEncryptor.java} (61%) create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 759a708..8b49ca9 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -28,7 +28,9 @@ message UIElement { bytes data = 2; } -// a new data structure for BallotQuestion. Need to delete the old one +// A question in the ballot +// is_mandatory determines whether the question may be skipped with no answer +// description might hold information/guidlines for the voter message BallotQuestion { bool is_mandatory = 1; UIElement question = 2; diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java index 32e3208..39eed6a 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -1,5 +1,6 @@ package meerkat.voting; +import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** @@ -7,13 +8,20 @@ import meerkat.protobuf.Voting.*; */ public interface BallotOutputDevice { - void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback); + /** + * + * @param requestId + * @param encryptedBallot + * @param callback + */ + void commitToBallot(int requestId, EncryptedBallot encryptedBallot, + FutureCallback> callback); - void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback); + void audit(int requestId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, + FutureCallback> callback); - void castBallot(long sessionId, VotingBooth.Callback callback); + void castBallot(int requestId, FutureCallback> callback); - // probably has no difference than cast. Maybe drop this method - void cancelBallot(long sessionId, VotingBooth.Callback callback); + void cancelBallot(int requestId, FutureCallback> callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java index 3edff7a..c05f383 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -1,12 +1,13 @@ package meerkat.voting; +import meerkat.protobuf.Voting; + /** * Created by hai on 23/02/16. */ public interface StorageManager { - // should these methods be synchronous or asynchronous? Can we rely on it being immediate? - public void detectAdminHardwareKey(); + boolean detectAdminHardwareKey(); - public void readElectionParams (); + Voting.ElectionParams readElectionParams (); } diff --git a/voting-booth/src/main/java/meerkat/voting/UI.java b/voting-booth/src/main/java/meerkat/voting/UI.java deleted file mode 100644 index 83739db..0000000 --- a/voting-booth/src/main/java/meerkat/voting/UI.java +++ /dev/null @@ -1,32 +0,0 @@ -package meerkat.voting; - -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 23/02/16. - */ -public interface UI { - - - // Voter scenario methods - void introductionToVoter (long sessionId); - - void chooseChannel (long sessionId, BallotQuestion question); - - void askVoterQuestion (long sessionId, int questionNumber, BallotQuestion question); - - void castOrAudit (long sessionId); - - void showWaitForFinishScreen (long sessionId); - - - // Admin scenario methods - //TODO: the admin scenario still needs some more thinking - - - - // bad thing happened scenario - void showErrorMessageAndHalt (String errorMessage); - void showErrorMessageWithCancelButton (long sessionId, String errorMessage); - -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index a7df483..9182eca 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -1,6 +1,5 @@ package meerkat.voting; -import meerkat.protobuf.Voting; import meerkat.protobuf.Voting.*; /** @@ -8,75 +7,21 @@ import meerkat.protobuf.Voting.*; */ public interface VotingBooth { - public enum ErrorID { - OUTPUT_DEVICE_OUT_OF_PAPER, - OUTPUT_DEVICE_OUT_OF_INK, - OUTPUT_DEVICE_NO_CONNECTION, - OUTPUT_DEVICE_HARDWARE_NOT_FOUND, + void setComponenets (BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); - UI_HARDWARE_NOT_FOUND - } + void initBoothParams (BoothParams boothParams); - - // keeps track in which state we are - // internal state will also include the number of the current question and the answers we got so far, - // later it includes the details of the PlaintextBallot and later the Encryption and the secrets - public enum State { - INITIALIZED, - - VOTER_INTRODUCTION, - VOTER_CHOOSE_CHANNEL, - VOTER_VOTING, - VOTER_ENCRYPTING, - VOTER_CAST_OR_AUDIT, - VOTER_CASTING, - VOTER_AUDITING - - } - - public interface Callback { - - // callbacks and messages from BallotOutputDevice - - public void ballotCommitResult (long sessionId, boolean result); - public void ballotCastResult (long sessionId, boolean result); - public void ballotAuditResult (long sessionId, boolean result); - public void ballotCancelResult (long sessionId, boolean result); - // other error messages, such as Printer turned-off or out-of-paper - public void outputDeviceReportProblem (ErrorID errorId); - - - // callbacks and messages from UI - - public void introductionFinished (long sessionId); - public void choiceOfChannel (long sessionId, int channelNumber); - public void skipQuestion (long sessionId, int questionNumber); - public void backwardsQuestion (long sessionId, int questionNumber); - public void cancelVotingSession (long sessionId); - public void answer (long sessionId, int questionNumber, String answer); - public void cast (long sessionId); - public void audit (long sessionId); - // other error messages, such as hardware-not-detected - public void uiReportProblem (ErrorID errorId); - - - // callbacks from encryptor - - public void returnEncryption (long sessionId, EncryptedBallot encryptedBallot, BallotSecrets secrets); - - - // callbacks from StorageManager - - public void adminHardwareKeyDetected (boolean isKeyInserted); - public void loadElectionParams (ElectionParams electionParams); - } + void initElectionParams (ElectionParams electionParams); // this function is synchronous - public void start (); + void start (); // messages from Admin Console (If there is such one) // this function is asynchronous - public void shutDown(); + void shutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/Encryptor.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java similarity index 61% rename from voting-booth/src/main/java/meerkat/voting/Encryptor.java rename to voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java index 4cfcf57..60384e9 100644 --- a/voting-booth/src/main/java/meerkat/voting/Encryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java @@ -5,9 +5,9 @@ import meerkat.protobuf.Voting.*; /** * Created by hai on 23/02/16. */ -public interface Encryptor { +public interface VotingBoothEncryptor { - public void encrypt (long sessionId, PlaintextBallot plaintextBallot); + void encrypt (PlaintextBallot plaintextBallot); //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java new file mode 100644 index 0000000..6702ce9 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java @@ -0,0 +1,17 @@ +package meerkat.voting; + +/** + * Created by hai on 02/03/16. + */ +public class VotingBoothResult { + private final int m_requestId; + private final T m_result; + + public int getRequestId () { return m_requestId; } + public T getResult () { return m_result; } + + public VotingBoothResult (int requestId, T result) { + m_requestId = requestId; + m_result = result; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java new file mode 100644 index 0000000..0726a09 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -0,0 +1,64 @@ +package meerkat.voting; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface VotingBoothUI { + + enum VoterQuestionChoice { + ANSWERED, + SKIP, + BACK, + CANCEL + } + + class VoterQuestionResponse { + private final VoterQuestionChoice m_choice; + private final String m_answer; + + public VoterQuestionResponse(VoterQuestionChoice choice, String answer) { + assert ((choice == VoterQuestionChoice.ANSWERED && answer != null) || + (choice != VoterQuestionChoice.ANSWERED && answer == null)); + m_choice = choice; + m_answer = answer; + } + + public VoterQuestionChoice getChoice () { return m_choice; } + public String getAnswer () { return m_answer; } + } + + + enum FinalizeBallotChoice { + CAST, + AUDIT + } + + // Voter scenario methods + void newVoter (int requestId, FutureCallback> callback); + + void chooseChannel (int requestId, BallotQuestion question, FutureCallback> callback); + + void askVoterQuestion (int requestId, int questionNumber, BallotQuestion question, + FutureCallback> callback); + + void castOrAudit (int requestId, FutureCallback> callback); + + void showWaitForFinishScreen (int requestId, FutureCallback> callback); + + + // Admin scenario methods + //TODO: the admin scenario still needs some more thinking + + + + // bad thing happened scenario + void showErrorMessageAndHalt (int requestId, String errorMessage, + FutureCallback> callback); + + void showErrorMessageWithButtons (int requestId, String errorMessage, String[] buttonLabels, + FutureCallback> callback); + +} From 0fa5d4094add0f4fc20a53ce2d54979ddf8537b8 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 13 Mar 2016 15:35:58 +0200 Subject: [PATCH 18/66] yet another take on the VB interfaces. Interfaces were now shortened even more. Many changes were made according to Arbel's instructions. Most important change is now that the controller passes ALL questions for UI to ask voter, instead of chunks of questions and back-and-forth messages between the controller and UI which were always quite redundant. --- .../meerkat/voting/BallotOutputDevice.java | 34 +++++--- .../java/meerkat/voting/StorageManager.java | 16 +++- .../main/java/meerkat/voting/VotingBooth.java | 37 ++++++--- .../meerkat/voting/VotingBoothEncryptor.java | 28 ++++++- .../meerkat/voting/VotingBoothResult.java | 17 ---- .../java/meerkat/voting/VotingBoothUI.java | 79 ++++++++++--------- 6 files changed, 131 insertions(+), 80 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java index 39eed6a..0199523 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -4,24 +4,36 @@ import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** - * Created by hai on 15/02/16. + * An interface for the device in which we output the ballots. + * Probably going to be a printer or an ethernet connection, or both. */ public interface BallotOutputDevice { /** - * - * @param requestId - * @param encryptedBallot - * @param callback + * Output the encrypted ballot. This is a commitment before voter chooses casting or auditing + * @param encryptedBallot - the encrypted ballot to commit to + * @param callback - a callback object through which to return a success flag */ - void commitToBallot(int requestId, EncryptedBallot encryptedBallot, - FutureCallback> callback); + public void commitToBallot(EncryptedBallot encryptedBallot, FutureCallback callback); - void audit(int requestId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, - FutureCallback> callback); + /** + * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. + * @param encryptedBallot - the encrypted ballot + * @param ballotSecrets - the secrtes of the encryption + * @param callback - a callback object through which to return a success flag + */ + public void audit(EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, FutureCallback callback); - void castBallot(int requestId, FutureCallback> callback); + /** + * Voter chose 'cast'. Finalize the ballot for use in the polling station + * @param callback - a callback object through which to return a success flag + */ + public void castBallot(FutureCallback callback); - void cancelBallot(int requestId, FutureCallback> callback); + /** + * Cancelling the current ballot. This clears the state of the OutputDevice if the implementation has any such state. + * @param callback - a callback object through which to return a success flag + */ + public void cancelBallot(FutureCallback callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java index c05f383..0fd18ca 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -1,13 +1,21 @@ package meerkat.voting; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the storage component of the voting booth */ public interface StorageManager { - boolean detectAdminHardwareKey(); + /** + * Detect whether an administration key is inserted to the machine. This determines if we gointo the set-up flow or the voting session flow. + * @return True is a hardware key is inserted. False if not. + */ + public boolean isAdminHardwareKeyInserted(); - Voting.ElectionParams readElectionParams (); + /** + * load the election params from a file. + * @return the current election params + */ + public ElectionParams readElectionParams (); } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index 9182eca..a2b211b 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -3,25 +3,42 @@ package meerkat.voting; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the controller component of the voting booth */ public interface VotingBooth { - void setComponenets (BallotOutputDevice outputDevice, + /** + * setting all the different components of the Voting Booth to be recognized by this controller + * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection + * @param vbEncryptor the encryption module + * @param vbUI User interface in which the voter chooses his answers + * @param vbStorageManager storage component for handling files and USB sticks + */ + public void setComponenets (BallotOutputDevice outputDevice, VotingBoothEncryptor vbEncryptor, VotingBoothUI vbUI, StorageManager vbStorageManager); - void initBoothParams (BoothParams boothParams); + /** + * initialize using the BoothParams protobuf + * @param boothParams + */ + public void initBoothParams (BoothParams boothParams); - void initElectionParams (ElectionParams electionParams); + /** + * set the voting questions + * @param questions + */ + public void setBallotQuestions (BallotQuestion[] questions); - // this function is synchronous - void start (); + /** + * a synchronous function. Starts running the controller component, and basically run the whole system for voting + */ + public void run (); - - // messages from Admin Console (If there is such one) - // this function is asynchronous - void shutDown(); + /** + * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system + */ + public void shutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java index 60384e9..cc9b7bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java @@ -1,13 +1,37 @@ package meerkat.voting; +import com.sun.org.apache.xml.internal.security.encryption.EncryptedType; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the encryptor component of the voting booth */ public interface VotingBoothEncryptor { - void encrypt (PlaintextBallot plaintextBallot); + /** + * A simple class for pairing EncrypedBallot together with its matching BallotSecrets + */ + public class EncryptionAndSecrets { + private final EncryptedBallot encryptedBallot; + private final BallotSecrets secrets; + + public EncryptionAndSecrets (EncryptedBallot encryptedBallot, BallotSecrets secrets) { + this.encryptedBallot = encryptedBallot; + this.secrets = secrets; + } + + public EncryptedBallot getEncryptedBallot () { return encryptedBallot; } + public BallotSecrets getSecrets() { return secrets; } + } + + + /** + * This function encrypts the plaintext ballot using the booth's keys + * @param plaintextBallot - all plaintext ballot info of the voter + * @return an encryption of the ballot + */ + public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot); + //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java deleted file mode 100644 index 6702ce9..0000000 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java +++ /dev/null @@ -1,17 +0,0 @@ -package meerkat.voting; - -/** - * Created by hai on 02/03/16. - */ -public class VotingBoothResult { - private final int m_requestId; - private final T m_result; - - public int getRequestId () { return m_requestId; } - public T getResult () { return m_result; } - - public VotingBoothResult (int requestId, T result) { - m_requestId = requestId; - m_result = result; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java index 0726a09..78ccfef 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -4,61 +4,68 @@ import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the user interface component of the voting booth */ public interface VotingBoothUI { - enum VoterQuestionChoice { - ANSWERED, - SKIP, - BACK, - CANCEL - } - - class VoterQuestionResponse { - private final VoterQuestionChoice m_choice; - private final String m_answer; - - public VoterQuestionResponse(VoterQuestionChoice choice, String answer) { - assert ((choice == VoterQuestionChoice.ANSWERED && answer != null) || - (choice != VoterQuestionChoice.ANSWERED && answer == null)); - m_choice = choice; - m_answer = answer; - } - - public VoterQuestionChoice getChoice () { return m_choice; } - public String getAnswer () { return m_answer; } - } - - enum FinalizeBallotChoice { CAST, AUDIT } - // Voter scenario methods - void newVoter (int requestId, FutureCallback> callback); + /** + * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning + * @param callback - a boolean future callback to return success when done + */ + public void startNewVoterSession (FutureCallback callback); - void chooseChannel (int requestId, BallotQuestion question, FutureCallback> callback); + /** + * Present a question to the voter to decide on his voting channel. + * @param question a question to determine the right voting channel for this voter + * @param callback that's where we store the channel for the current voter + */ + public void chooseChannel (BallotQuestion question, FutureCallback callback); - void askVoterQuestion (int requestId, int questionNumber, BallotQuestion question, - FutureCallback> callback); + /** + * Presents the set of questions to the voter. Collect all his responses. + * @param questions all ballot questions to present to the voter + * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session + */ + public void askVoterQuestions (BallotQuestion[] questions, FutureCallback callback); - void castOrAudit (int requestId, FutureCallback> callback); + /** + * Get a response from the voter on how to finalize the ballot. + * @param callback the returned choice of how to finalize the ballot + */ + public void castOrAudit (FutureCallback callback); - void showWaitForFinishScreen (int requestId, FutureCallback> callback); // Admin scenario methods //TODO: the admin scenario still needs some more thinking + /** + * present a wait-for-finish screen to the voter + * @param message a message to show the user on the UI device while waiting + * @param callback a success return value of the wait (cancelling returns false) + */ + public void askVoterToWaitForFinish (String message, FutureCallback callback); - // bad thing happened scenario - void showErrorMessageAndHalt (int requestId, String errorMessage, - FutureCallback> callback); + /** + * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset + * @param errorMessage message to show in UI device + * @param callback returns interrupt + */ + public void showErrorMessageAndHalt (String errorMessage, FutureCallback callback); - void showErrorMessageWithButtons (int requestId, String errorMessage, String[] buttonLabels, - FutureCallback> callback); + /** + * show an error message and let user press his chosen button for continuation + * @param errorMessage message to show in UI device + * @param buttonLabels labels for buttons to present to voter + * @param callback the number of the selected button + */ + public void showErrorMessageWithButtons (String errorMessage, String[] buttonLabels, + FutureCallback callback); } From d1bc0d7c844d1facfbea85d2df48fef3e5cf42a2 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Fri, 18 Mar 2016 10:22:05 +0200 Subject: [PATCH 19/66] Some small changes according to code review --- .../main/java/meerkat/voting/VotingBooth.java | 18 +++++++----------- .../java/meerkat/voting/VotingBoothUI.java | 10 +++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index a2b211b..9ef863c 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -8,22 +8,18 @@ import meerkat.protobuf.Voting.*; public interface VotingBooth { /** - * setting all the different components of the Voting Booth to be recognized by this controller + * initialize using the BoothParams protobuf and sett all the different components of the Voting Booth to be recognized by this controller + * @param boothParams * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection * @param vbEncryptor the encryption module * @param vbUI User interface in which the voter chooses his answers * @param vbStorageManager storage component for handling files and USB sticks */ - public void setComponenets (BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, - VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * initialize using the BoothParams protobuf - * @param boothParams - */ - public void initBoothParams (BoothParams boothParams); + public void init (BoothParams boothParams, + BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); /** * set the voting questions diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java index 78ccfef..c2ccfea 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -8,7 +8,7 @@ import meerkat.protobuf.Voting.*; */ public interface VotingBoothUI { - enum FinalizeBallotChoice { + public static enum FinalizeBallotChoice { CAST, AUDIT } @@ -24,7 +24,7 @@ public interface VotingBoothUI { * @param question a question to determine the right voting channel for this voter * @param callback that's where we store the channel for the current voter */ - public void chooseChannel (BallotQuestion question, FutureCallback callback); + public void chooseChannel (BallotQuestion question, FutureCallback callback); /** * Presents the set of questions to the voter. Collect all his responses. @@ -50,14 +50,14 @@ public interface VotingBoothUI { * @param message a message to show the user on the UI device while waiting * @param callback a success return value of the wait (cancelling returns false) */ - public void askVoterToWaitForFinish (String message, FutureCallback callback); + public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); /** * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset * @param errorMessage message to show in UI device * @param callback returns interrupt */ - public void showErrorMessageAndHalt (String errorMessage, FutureCallback callback); + public void showErrorMessageAndHalt (UIElement errorMessage, FutureCallback callback); /** * show an error message and let user press his chosen button for continuation @@ -65,7 +65,7 @@ public interface VotingBoothUI { * @param buttonLabels labels for buttons to present to voter * @param callback the number of the selected button */ - public void showErrorMessageWithButtons (String errorMessage, String[] buttonLabels, + public void showErrorMessageWithButtons (UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback); } From b7e543e5e8b81da6f72ea7b76c3356f6e183aff2 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 20 Mar 2016 16:15:43 +0200 Subject: [PATCH 20/66] simple rerandomize test --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../src/test/java/mixer/CreateTestVector.java | 4 +- .../src/test/java/mixer/RerandomizeTest.java | 16 +++- .../java/mixer/SimpleRerandomizeTest.java | 89 +++++++++++++++++++ 4 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 mixer/src/test/java/mixer/SimpleRerandomizeTest.java diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b99caa4..98af882 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Sun Dec 27 09:28:01 IST 2015 +#Sun Mar 20 15:13:00 IST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/mixer/src/test/java/mixer/CreateTestVector.java b/mixer/src/test/java/mixer/CreateTestVector.java index fcb273b..52f07fa 100644 --- a/mixer/src/test/java/mixer/CreateTestVector.java +++ b/mixer/src/test/java/mixer/CreateTestVector.java @@ -68,7 +68,7 @@ public class CreateTestVector { } return result; } - //@Test + //@SimpleRerandomizeTest public void createValidTest() throws IOException { List mixerInput = generateMixerInput(); @@ -81,7 +81,7 @@ public class CreateTestVector { System.out.println("all done"); } - //@Test + //@SimpleRerandomizeTest public void createInvalidTest() throws IOException { //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(encryptor,randomOracle,true); diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index c607f61..c2f0bb7 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -62,10 +62,18 @@ public class RerandomizeTest { ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e); ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew); - assert (g.multiply(new BigInteger(r.getData().toByteArray())).equals( - group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))))); - assert(h.multiply(new BigInteger(r.getData().toByteArray())).equals( - group.add(convert2ECPoint(eNewElGamal.getC2()), group.negate(convert2ECPoint(eElGamal.getC2()))))); + ECPoint expected1 = g.multiply(new BigInteger(r.getData().toByteArray())); + ECPoint result1 = group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))); + expected1.normalize(); + result1.normalize(); + assert (expected1.equals(result1)); + + ECPoint expected2 = h.multiply(new BigInteger(r.getData().toByteArray())); + ECPoint result2 = group.add(convert2ECPoint(eNewElGamal.getC2()), group.negate(convert2ECPoint(eElGamal.getC2()))); + expected2.normalize(); + result2.normalize(); + + assert (expected2.equals(result2)); } @Test diff --git a/mixer/src/test/java/mixer/SimpleRerandomizeTest.java b/mixer/src/test/java/mixer/SimpleRerandomizeTest.java new file mode 100644 index 0000000..b907e86 --- /dev/null +++ b/mixer/src/test/java/mixer/SimpleRerandomizeTest.java @@ -0,0 +1,89 @@ +package mixer; + +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 3/20/2016. + */ +public class SimpleRerandomizeTest { + + Random rand; + ECGroup group; + ECPoint g ; + ECPoint h ; + BigInteger sk; + @Before + public void setup() throws Exception { + rand = new Random(); + group = new ECGroup("secp256k1"); + g = group.getGenerator(); + sk = random(); + h = g.multiply(sk); + } + + public BigInteger random(){ + return new BigInteger(256,rand).mod(group.orderUpperBound()); + } + + public ECPoint randomMessage(){ + return group.sample(rand); + } + + public Encryption encrypt(ECPoint message,BigInteger randomness){ + return new Encryption(g.multiply(randomness), message.add(h.multiply(randomness))); + } + + public Encryption rerandomize(Encryption encryption,BigInteger randomness){ + return new Encryption(encryption.a.add(g.multiply(randomness)),encryption.b.add(h.multiply(randomness))); + } + + public ECPoint decrypt(Encryption encryption){ + return encryption.a.multiply(sk).negate().add(encryption.b); + } + + public class Encryption{ + ECPoint a,b; + Encryption(ECPoint a, ECPoint b){ + this.a = a; + this.b = b; + } + } + + public void oneRerandomizeTest(){ + ECPoint message = randomMessage(); + Encryption e = encrypt(message,random()); + BigInteger r = random(); + Encryption eNew = rerandomize(e,r); + assert (decrypt(e).equals(message)); + assert (decrypt(eNew).equals(message)); + + ECPoint expected1 = g.multiply(r); + ECPoint result1 = group.add(eNew.a,e.a.negate()); + expected1.normalize(); + result1.normalize(); + assert (expected1.equals(result1)); + + ECPoint expected2 = h.multiply(r); + ECPoint result2 = group.add(eNew.b,e.b.negate()); + expected2.normalize(); + result2.normalize(); + assert (expected2.equals(result2)); + } + + + @org.junit.Test + public void rerandomizeTest(){ + + int tests = 1000; + + for (int i = 0; i < tests; i ++){ + System.out.println("rerandomize test #" + i); + oneRerandomizeTest(); + } + } +} From e27fddcf0ce5be72711d44154cd7f74766cd4d80 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 20 Mar 2016 19:18:23 +0200 Subject: [PATCH 21/66] mixing test passed --- .../crypto/concrete/ECElGamalEncryption.java | 4 ++++ .../java/meerkat/crypto/mixnet/MixerOutput.java | 2 +- mixer/src/main/java/main/BatchConverter.java | 2 +- mixer/src/main/java/mixer/Mixer.java | 5 +++-- mixer/src/main/java/mixer/MixerOutput.java | 7 ++----- mixer/src/main/java/prover/Prover.java | 16 ++++++++-------- mixer/src/main/java/verifier/Verifier.java | 2 +- mixer/src/main/java/verifier/VerifyTable.java | 12 ++++++++---- mixer/src/test/java/mixer/MixingText.java | 2 +- mixer/src/test/java/mixer/RerandomizeTest.java | 6 ++++-- mixer/src/test/java/mixer/Utiles.java | 1 + .../test/java/mixer/ZeroKnowledgeProofTest.java | 8 ++++---- .../test/java/profiling/BigInteger/AddSub.java | 2 -- .../profiling/BigInteger/GenerateRandomness.java | 3 +-- .../test/java/profiling/BigInteger/Modulo.java | 2 -- .../src/test/java/profiling/BigInteger/Mul.java | 2 -- .../test/java/profiling/BigInteger/SHA256.java | 2 -- .../profiling/Convert/ByteString2ECPoint.java | 2 -- ...izableEncryptedMessage2ElGamalCiphertext.java | 3 +-- mixer/src/test/java/profiling/ECGroup/Add.java | 2 -- .../src/test/java/profiling/ECGroup/Encode.java | 4 ++-- mixer/src/test/java/profiling/ECGroup/Mul.java | 3 +-- .../src/test/java/profiling/ECGroup/Negate.java | 3 +-- mixer/src/test/java/profiling/Rerandomize.java | 2 -- .../test/java/profiling/ZeroKnowledgeProof.java | 3 +-- 25 files changed, 45 insertions(+), 55 deletions(-) diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 5dae4b7..4946b44 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -146,4 +146,8 @@ public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption return retval; } + + public BigInteger extractRandomness(Crypto.EncryptionRandomness encryptionRandomness){ + return new BigInteger(1,encryptionRandomness.getData().toByteArray()); + } } diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java index 9ae1432..eb71e61 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java @@ -7,7 +7,7 @@ import meerkat.protobuf.Mixing; * Created by Tzlil on 1/18/2016. */ public interface MixerOutput { - public Mixing.ZeroKnowledgeProof[][] gerProofs(); + public Mixing.ZeroKnowledgeProof[][] getProofs(); public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages(); public int getN(); } diff --git a/mixer/src/main/java/main/BatchConverter.java b/mixer/src/main/java/main/BatchConverter.java index 919f406..c4e3404 100644 --- a/mixer/src/main/java/main/BatchConverter.java +++ b/mixer/src/main/java/main/BatchConverter.java @@ -38,7 +38,7 @@ public class BatchConverter { .setData(Integer2ByteString(n)) .build()); - for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.gerProofs()) { + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) { for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { result.add(BulletinBoardAPI.BatchData.newBuilder() .setData(zkp.toByteString()) diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index 477e740..c2c52c0 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -100,11 +100,13 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { protected ZeroKnowledgeProof[][] createZKPTable(int n,int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { - ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][n]; Switch[] switchesLayer; int index1,index2; int switchIndex = 0; int nDiv2 = n >> 1; + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + + RerandomizableEncryptedMessage e1,e2; EncryptionRandomness r1,r2; for (int layer = 0; layer < layers; layer++) @@ -132,7 +134,6 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { public MixerOutput mix(List ciphertexts) throws InvalidProtocolBufferException { int n = ciphertexts.size(); - int nDiv2 = n >> 1; if (!inputBasicCheckSum(n)) return null; diff --git a/mixer/src/main/java/mixer/MixerOutput.java b/mixer/src/main/java/mixer/MixerOutput.java index 38ad3c8..c8efda6 100644 --- a/mixer/src/main/java/mixer/MixerOutput.java +++ b/mixer/src/main/java/mixer/MixerOutput.java @@ -3,12 +3,9 @@ package mixer; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import java.awt.*; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.Files; /** @@ -28,7 +25,7 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ } public MixerOutput(meerkat.crypto.mixnet.MixerOutput mixerOutput) { - this.proofs = mixerOutput.gerProofs(); + this.proofs = mixerOutput.getProofs(); this.encryptedMessages = mixerOutput.getEncryptedMessages(); this.n = mixerOutput.getN(); this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1; @@ -36,7 +33,7 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ @Override - public Mixing.ZeroKnowledgeProof[][] gerProofs() { + public Mixing.ZeroKnowledgeProof[][] getProofs() { return proofs; } diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 93fba71..0ff8494 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -99,7 +99,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { */ private BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { byte[] arr = input.toByteArray(); - return new BigInteger(this.randomOracle.hash(arr,arr.length)); + return new BigInteger(1,this.randomOracle.hash(arr,arr.length)); } @@ -120,7 +120,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { ECPoint g2Tag = orProofInput.g2Tag; ECPoint h2Tag = orProofInput.h2Tag; - BigInteger r = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); + BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); BigInteger c1,c2,z,zTag; ECPoint u,v,uTag,vTag; Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; @@ -128,8 +128,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { switch (orProofInput.flag) { case left: - c2 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); - zTag = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); + c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); //step 1 u = group.multiply(g1, r); v = group.multiply(g2, r); @@ -155,11 +155,11 @@ public class Prover implements Mix2ZeroKnowledgeProver { c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); //step 3 //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(groupOrderUpperBound); + z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); break; case right: - c1 = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); - z = new BigInteger(encryptor.generateRandomness(rand).getData().toByteArray()).mod(groupOrderUpperBound); + c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); //step 1 uTag = group.multiply(g1Tag, r); vTag = group.multiply(g2Tag, r); @@ -185,7 +185,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); //step 3 //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(new BigInteger(orProofInput.x.getData().toByteArray()))).mod(groupOrderUpperBound); + zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); break; default: return null; diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index 94c6084..308521f 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -37,7 +37,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { byte[] arr = input.toByteArray(); - return new BigInteger(this.randomOracle.hash(arr,arr.length)); + return new BigInteger(1,this.randomOracle.hash(arr,arr.length)); } /** * @return true iff the proof is valid diff --git a/mixer/src/main/java/verifier/VerifyTable.java b/mixer/src/main/java/verifier/VerifyTable.java index 37fdedb..ebf203c 100644 --- a/mixer/src/main/java/verifier/VerifyTable.java +++ b/mixer/src/main/java/verifier/VerifyTable.java @@ -5,7 +5,6 @@ import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; -import qilin.util.Pair; import java.util.Arrays; @@ -30,11 +29,16 @@ public final class VerifyTable { Arrays.fill(locationChecksumLayer,false); } - Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.gerProofs(); + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs(); Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); - for (Mixing.ZeroKnowledgeProof[] zkpLayer: zeroKnowledgeProofs) { - for (Mixing.ZeroKnowledgeProof zkp: zkpLayer) { + for (int i = 0; i < zeroKnowledgeProofs.length ; i++){ + for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){ + Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j]; + if(zkp == null){ + int ttt = 1; + ttt++; + } Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); index1 = location.getI(); index2 = location.getJ(); diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index 23645ed..e2d0b6f 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -53,7 +53,7 @@ public class MixingText { mixer = new Mixer(randomMixer,prover,encryptor); // generate n - int logN = 10; // + random.nextInt(8) + int logN = 8; // + random.nextInt(8) layers = 2*logN - 1; n = 1 << logN; } diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index c2f0bb7..b7d9082 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -7,6 +7,7 @@ import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; import org.junit.Before; import org.junit.Test; import qilin.primitives.RandomOracle; @@ -62,13 +63,13 @@ public class RerandomizeTest { ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e); ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew); - ECPoint expected1 = g.multiply(new BigInteger(r.getData().toByteArray())); + ECPoint expected1 = g.multiply(enc.extractRandomness(r)); ECPoint result1 = group.add(convert2ECPoint(eNewElGamal.getC1()),group.negate(convert2ECPoint(eElGamal.getC1()))); expected1.normalize(); result1.normalize(); assert (expected1.equals(result1)); - ECPoint expected2 = h.multiply(new BigInteger(r.getData().toByteArray())); + ECPoint expected2 = h.multiply(enc.extractRandomness(r)); ECPoint result2 = group.add(convert2ECPoint(eNewElGamal.getC2()), group.negate(convert2ECPoint(eElGamal.getC2()))); expected2.normalize(); result2.normalize(); @@ -76,6 +77,7 @@ public class RerandomizeTest { assert (expected2.equals(result2)); } + @Test public void rerandomizeTest() throws InvalidProtocolBufferException { diff --git a/mixer/src/test/java/mixer/Utiles.java b/mixer/src/test/java/mixer/Utiles.java index 2be2a1c..15483f3 100644 --- a/mixer/src/test/java/mixer/Utiles.java +++ b/mixer/src/test/java/mixer/Utiles.java @@ -18,6 +18,7 @@ import qilin.primitives.generic.ElGamal; import qilin.util.Pair; import java.io.ByteArrayInputStream; +import java.math.BigInteger; import java.security.KeyFactory; import java.security.PublicKey; import java.util.Random; diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index 5bfedc8..6b75b1a 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -76,13 +76,13 @@ public class ZeroKnowledgeProofTest { ConcreteCrypto.ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e2New); - assert (g.multiply(new BigInteger(r1.getData().toByteArray())).equals( + assert (g.multiply(enc.extractRandomness(r1)).equals( group.add(convert2ECPoint(e1TagElGamal.getC1()),group.negate(convert2ECPoint(e1ElGamal.getC1()))))); - assert (h.multiply(new BigInteger(r1.getData().toByteArray())).equals( + assert (h.multiply(enc.extractRandomness(r1)).equals( group.add(convert2ECPoint(e1TagElGamal.getC2()),group.negate(convert2ECPoint(e1ElGamal.getC2()))))); - assert (g.multiply(new BigInteger(r2.getData().toByteArray())).equals( + assert (g.multiply(enc.extractRandomness(r2)).equals( group.add(convert2ECPoint(e2TagElGamal.getC1()),group.negate(convert2ECPoint(e2ElGamal.getC1()))))); - assert (h.multiply(new BigInteger(r2.getData().toByteArray())).equals( + assert (h.multiply(enc.extractRandomness(r2)).equals( group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))))); assert (verifier.verify(e1,e2,e1New,e2New,prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2))); diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java index 1505aca..86ef2a7 100644 --- a/mixer/src/test/java/profiling/BigInteger/AddSub.java +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -23,7 +23,6 @@ public class AddSub { BigInteger[] randoms; BigInteger[] randoms2; - @Before public void setup() throws Exception { Random rand = new Random(); tests = 1 << 17; @@ -47,7 +46,6 @@ public class AddSub { } - @Test public void AddSubProfiling() throws InvalidProtocolBufferException { System.out.println("AddSub"); diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java index 837fcc5..870d331 100644 --- a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -19,7 +19,7 @@ public class GenerateRandomness { int tests; ECElGamalEncryption enc; Random rand; - @Before + public void setup() throws Exception { rand = new Random(); ECGroup group = new ECGroup("secp256k1"); @@ -33,7 +33,6 @@ public class GenerateRandomness { } - @Test public void GenerateRandomnessProfiling() throws InvalidProtocolBufferException { System.out.println("GenerateRandomnessProfiling"); diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java index a1757ee..a97cf6c 100644 --- a/mixer/src/test/java/profiling/BigInteger/Modulo.java +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -23,7 +23,6 @@ public class Modulo { BigInteger[] randoms; BigInteger orderUpperBound; - @Before public void setup() throws Exception { Random rand = new Random(); ECGroup group = new ECGroup("secp256k1"); @@ -41,7 +40,6 @@ public class Modulo { } } - @Test public void ModuloProfiling() throws InvalidProtocolBufferException { System.out.println("ModuloProfiling"); diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java index 9656255..c25a1d8 100644 --- a/mixer/src/test/java/profiling/BigInteger/Mul.java +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -21,7 +21,6 @@ public class Mul { BigInteger[] randoms; BigInteger[] randoms2; - @Before public void setup() throws Exception { Random rand = new Random(); tests = 1 << 17; @@ -45,7 +44,6 @@ public class Mul { } - @Test public void MulProfiling() throws InvalidProtocolBufferException { System.out.println("Mul"); diff --git a/mixer/src/test/java/profiling/BigInteger/SHA256.java b/mixer/src/test/java/profiling/BigInteger/SHA256.java index 7e086a4..c2f4cbc 100644 --- a/mixer/src/test/java/profiling/BigInteger/SHA256.java +++ b/mixer/src/test/java/profiling/BigInteger/SHA256.java @@ -26,7 +26,6 @@ public class SHA256 { BigInteger[] randoms; RandomOracle randomOracle; - @Before public void setup() throws Exception { Random rand = new Random(); randomOracle = new DigestOracle(); @@ -40,7 +39,6 @@ public class SHA256 { } } - @Test public void SHA256Profiling() throws InvalidProtocolBufferException { System.out.println("SHA256Profiling"); diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index 77d1a68..c11d718 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -28,7 +28,6 @@ public class ByteString2ECPoint { int tests; ConcreteCrypto.ElGamalCiphertext[] encryptedMessage; - @Before public void setup() throws Exception { rand = new Random(); group = new ECGroup("secp256k1"); @@ -53,7 +52,6 @@ public class ByteString2ECPoint { return group.decode(bs.toByteArray()); } - @Test public void ByteString2ECPointProfiling() throws InvalidProtocolBufferException { System.out.println("ByteString2ECPointProfiling"); diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java index 8639911..316070d 100644 --- a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -28,7 +28,6 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext { int tests; Crypto.RerandomizableEncryptedMessage[] encryptedMessage; - @Before public void setup() throws Exception { rand = new Random(); group = new ECGroup("secp256k1"); @@ -48,7 +47,7 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext { encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); } } - @Test + public void RerandomizableEncryptedMessage2ElGamalCiphertext() throws InvalidProtocolBufferException { System.out.println("RerandomizableEncryptedMessage2ElGamalCiphertext"); diff --git a/mixer/src/test/java/profiling/ECGroup/Add.java b/mixer/src/test/java/profiling/ECGroup/Add.java index 31865b9..c45457e 100644 --- a/mixer/src/test/java/profiling/ECGroup/Add.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -26,7 +26,6 @@ public class Add { List members1; List members2; - @Before public void setup() throws InvalidKeySpecException { // initialization random = new Random(); @@ -46,7 +45,6 @@ public class Add { } } - @Test public void addProfiling() throws InvalidProtocolBufferException { System.out.println("AddSub"); System.out.println("n is : " + n); diff --git a/mixer/src/test/java/profiling/ECGroup/Encode.java b/mixer/src/test/java/profiling/ECGroup/Encode.java index a7a731f..ccdf3cb 100644 --- a/mixer/src/test/java/profiling/ECGroup/Encode.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -25,7 +25,7 @@ public class Encode { private int n; List members; - @Before + public void setup() throws InvalidKeySpecException { // initialization random = new Random(); @@ -41,7 +41,7 @@ public class Encode { members.add(group.sample(random)); } } - @Test + public void encodeProfiling() throws InvalidProtocolBufferException { System.out.println("Encode"); System.out.println("n is : " + n); diff --git a/mixer/src/test/java/profiling/ECGroup/Mul.java b/mixer/src/test/java/profiling/ECGroup/Mul.java index b0c0c7e..bb7ecaf 100644 --- a/mixer/src/test/java/profiling/ECGroup/Mul.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -26,7 +26,7 @@ public class Mul { private int n; List members; List randomnesses; - @Before + public void setup() throws InvalidKeySpecException { // initialization random = new Random(); @@ -48,7 +48,6 @@ public class Mul { } } - @Test public void mulProfiling() throws InvalidProtocolBufferException { System.out.println("Multiply"); System.out.println("n is : " + n); diff --git a/mixer/src/test/java/profiling/ECGroup/Negate.java b/mixer/src/test/java/profiling/ECGroup/Negate.java index 75030fa..0c2d9d7 100644 --- a/mixer/src/test/java/profiling/ECGroup/Negate.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -25,7 +25,6 @@ public class Negate { private int n; List members; - @Before public void setup() throws InvalidKeySpecException { // initialization random = new Random(); @@ -41,7 +40,7 @@ public class Negate { members.add(group.sample(random)); } } - @Test + public void negProfiling() throws InvalidProtocolBufferException { System.out.println("Neg"); System.out.println("n is : " + n); diff --git a/mixer/src/test/java/profiling/Rerandomize.java b/mixer/src/test/java/profiling/Rerandomize.java index ed018f3..495c7ca 100644 --- a/mixer/src/test/java/profiling/Rerandomize.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -34,7 +34,6 @@ public class Rerandomize { Crypto.EncryptionRandomness[] randomnesses; Crypto.RerandomizableEncryptedMessage[] encryptedMessage; - @Before public void setup() throws Exception { rand = new Random(); group = new ECGroup("secp256k1"); @@ -58,7 +57,6 @@ public class Rerandomize { } } - @Test public void RerandomizeProfiling() throws InvalidProtocolBufferException { System.out.println("Rerandomiz"); diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index c371d7b..356e69a 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -37,7 +37,7 @@ public class ZeroKnowledgeProof { Crypto.EncryptionRandomness[] randomnesses; Crypto.RerandomizableEncryptedMessage[] encryptedMessage; Crypto.RerandomizableEncryptedMessage[] reencryptedMessage; - @Before + public void setup() throws Exception { rand = new Random(); group = new ECGroup("secp256k1"); @@ -70,7 +70,6 @@ public class ZeroKnowledgeProof { return group.decode(bs.toByteArray()); } - @Test public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException { System.out.println("Prove"); From 19e52344f56a0d5e6eca4c2ddaa66cc78f2be444 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Tue, 5 Apr 2016 11:49:34 +0300 Subject: [PATCH 22/66] Merged move to public qilin version --- gradle/wrapper/gradle-wrapper.properties.orig | 11 ++++++++ meerkat-common/build.gradle | 2 +- .../java/meerkat/crypto/mixnet/Mixer.java | 2 -- mixer/build.gradle | 3 +++ mixer/src/main/java/mixer/Mixer.java | 25 +++++++------------ .../java/prover/ElGamalProofOrganizer.java | 2 +- mixer/src/main/java/prover/Prover.java | 4 +-- mixer/src/main/java/verifier/Verifier.java | 4 +-- .../verifier/ZeroKnowledgeOrProofParser.java | 2 +- .../src/test/java/mixer/CreateTestVector.java | 10 +++----- mixer/src/test/java/mixer/MixingText.java | 13 +++++----- .../src/test/java/mixer/RerandomizeTest.java | 9 +++---- .../java/mixer/SimpleRerandomizeTest.java | 2 +- mixer/src/test/java/mixer/Utiles.java | 8 +++--- .../java/mixer/ZeroKnowledgeProofTest.java | 9 ++++--- .../java/profiling/BigInteger/AddSub.java | 8 ++---- .../BigInteger/GenerateRandomness.java | 6 ++--- .../java/profiling/BigInteger/Modulo.java | 9 ++----- .../test/java/profiling/BigInteger/Mul.java | 6 ++--- .../java/profiling/BigInteger/SHA256.java | 13 ++-------- .../profiling/Convert/ByteString2ECPoint.java | 7 ++---- ...bleEncryptedMessage2ElGamalCiphertext.java | 8 ++---- .../src/test/java/profiling/ECGroup/Add.java | 6 ++--- .../test/java/profiling/ECGroup/Encode.java | 6 ++--- .../src/test/java/profiling/ECGroup/Mul.java | 6 ++--- .../test/java/profiling/ECGroup/Negate.java | 6 ++--- .../src/test/java/profiling/Rerandomize.java | 12 ++------- .../java/profiling/ZeroKnowledgeProof.java | 12 +++------ settings.gradle.orig | 11 ++++++++ 29 files changed, 93 insertions(+), 129 deletions(-) create mode 100644 gradle/wrapper/gradle-wrapper.properties.orig create mode 100644 settings.gradle.orig diff --git a/gradle/wrapper/gradle-wrapper.properties.orig b/gradle/wrapper/gradle-wrapper.properties.orig new file mode 100644 index 0000000..1384b44 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties.orig @@ -0,0 +1,11 @@ +<<<<<<< HEAD +#Sun Mar 20 15:13:00 IST 2016 +======= +#Tue Aug 05 03:26:05 IDT 2014 +>>>>>>> e8e511d9ce636a127bb33d70ebfd9b2f230c6e1d +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip +distributionSha256Sum=4647967f8de78d6d6d8093cdac50f368f8c2b8038f41a5afe1c3bce4c69219a9 diff --git a/meerkat-common/build.gradle b/meerkat-common/build.gradle index c510e0a..b44b1fe 100644 --- a/meerkat-common/build.gradle +++ b/meerkat-common/build.gradle @@ -49,7 +49,7 @@ dependencies { compile 'com.google.guava:guava:11.0.+' // Crypto - compile 'org.factcenter.qilin:qilin:1.2+' + compile 'org.factcenter.qilin:qilin:1.2.+' compile 'org.bouncycastle:bcprov-jdk15on:1.53' testCompile 'junit:junit:4.+' diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 5a0834f..4262012 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -1,9 +1,7 @@ package meerkat.crypto.mixnet; import com.google.protobuf.InvalidProtocolBufferException; -import qilin.util.Pair; import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; import java.util.List; diff --git a/mixer/build.gradle b/mixer/build.gradle index 14cb9dd..ba26598 100644 --- a/mixer/build.gradle +++ b/mixer/build.gradle @@ -49,6 +49,9 @@ dependencies { // Google protobufs compile 'com.google.protobuf:protobuf-java:3.+' + // Crypto + compile 'org.factcenter.qilin:qilin:1.2.+' + testCompile 'junit:junit:4.+' runtime 'org.codehaus.groovy:groovy:2.4.+' diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java index c2c52c0..ddee9f9 100644 --- a/mixer/src/main/java/mixer/Mixer.java +++ b/mixer/src/main/java/mixer/Mixer.java @@ -1,24 +1,17 @@ package mixer; -import java.math.*; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.crypto.mixnet.MixerOutput; -import qilin.primitives.concrete.ECGroup; -import qilin.util.Pair; -import java.util.Random; - import com.google.protobuf.InvalidProtocolBufferException; - -import meerkat.protobuf.Crypto.*; -import meerkat.protobuf.Mixing.*; - import meerkat.crypto.Encryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import verifier.Verifier; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto.EncryptionRandomness; +import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage; +import meerkat.protobuf.Mixing.ZeroKnowledgeProof; + +import java.math.BigInteger; +import java.util.List; +import java.util.Random; public class Mixer implements meerkat.crypto.mixnet.Mixer { diff --git a/mixer/src/main/java/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/prover/ElGamalProofOrganizer.java index 540e944..d37713b 100644 --- a/mixer/src/main/java/prover/ElGamalProofOrganizer.java +++ b/mixer/src/main/java/prover/ElGamalProofOrganizer.java @@ -6,7 +6,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import org.bouncycastle.math.ec.ECPoint; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECGroup; /** * use for organize the input for each ZKP diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java index 0ff8494..90fdb75 100644 --- a/mixer/src/main/java/prover/Prover.java +++ b/mixer/src/main/java/prover/Prover.java @@ -7,8 +7,8 @@ import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java index 308521f..21c9520 100644 --- a/mixer/src/main/java/verifier/Verifier.java +++ b/mixer/src/main/java/verifier/Verifier.java @@ -7,8 +7,8 @@ import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; import prover.ElGamalProofOrganizer; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.ArrayList; diff --git a/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java index d3f82a5..e0695bc 100644 --- a/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java +++ b/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java @@ -3,7 +3,7 @@ package verifier; import com.google.protobuf.ByteString; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; diff --git a/mixer/src/test/java/mixer/CreateTestVector.java b/mixer/src/test/java/mixer/CreateTestVector.java index 52f07fa..591b397 100644 --- a/mixer/src/test/java/mixer/CreateTestVector.java +++ b/mixer/src/test/java/mixer/CreateTestVector.java @@ -1,18 +1,16 @@ package mixer; -import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; -import org.junit.Test; import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; import verifier.Verifier; import verifier.VerifyTable; diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index e2d0b6f..dc003be 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -6,20 +6,19 @@ package mixer; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.*; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; import meerkat.protobuf.Voting; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; -import qilin.util.Pair; import verifier.Verifier; import verifier.VerifyTable; + import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.List; diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index b7d9082..66b0343 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -7,13 +7,12 @@ import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.bouncycastle.math.ec.ECPoint; -import org.bouncycastle.util.BigIntegers; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/mixer/SimpleRerandomizeTest.java b/mixer/src/test/java/mixer/SimpleRerandomizeTest.java index b907e86..34df02b 100644 --- a/mixer/src/test/java/mixer/SimpleRerandomizeTest.java +++ b/mixer/src/test/java/mixer/SimpleRerandomizeTest.java @@ -1,8 +1,8 @@ package mixer; import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; -import qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/mixer/Utiles.java b/mixer/src/test/java/mixer/Utiles.java index 15483f3..0bb0e36 100644 --- a/mixer/src/test/java/mixer/Utiles.java +++ b/mixer/src/test/java/mixer/Utiles.java @@ -12,10 +12,10 @@ import meerkat.protobuf.Voting; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.math.ec.ECPoint; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; -import qilin.primitives.generic.ElGamal; -import qilin.util.Pair; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.generic.ElGamal; +import org.factcenter.qilin.util.Pair; import java.io.ByteArrayInputStream; import java.math.BigInteger; diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index 6b75b1a..4e9b404 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -9,14 +9,15 @@ import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; import verifier.Verifier; + import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java index 86ef2a7..b7cca3f 100644 --- a/mixer/src/test/java/profiling/BigInteger/AddSub.java +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -3,13 +3,9 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Voting; import mixer.Utiles; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java index 870d331..8711ab4 100644 --- a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import mixer.Utiles; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java index a97cf6c..8d2a6b9 100644 --- a/mixer/src/test/java/profiling/BigInteger/Modulo.java +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -3,14 +3,9 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Voting; import mixer.Utiles; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java index c25a1d8..b7d8730 100644 --- a/mixer/src/test/java/profiling/BigInteger/Mul.java +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import mixer.Utiles; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/SHA256.java b/mixer/src/test/java/profiling/BigInteger/SHA256.java index c2f4cbc..0db8279 100644 --- a/mixer/src/test/java/profiling/BigInteger/SHA256.java +++ b/mixer/src/test/java/profiling/BigInteger/SHA256.java @@ -1,18 +1,9 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; import meerkat.protobuf.Voting; -import mixer.Utiles; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index c11d718..931e0e3 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -4,14 +4,11 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java index 316070d..18625d0 100644 --- a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -1,17 +1,13 @@ package profiling.Convert; -import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import mixer.Utiles; -import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/ECGroup/Add.java b/mixer/src/test/java/profiling/ECGroup/Add.java index c45457e..ceadc43 100644 --- a/mixer/src/test/java/profiling/ECGroup/Add.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; diff --git a/mixer/src/test/java/profiling/ECGroup/Encode.java b/mixer/src/test/java/profiling/ECGroup/Encode.java index ccdf3cb..57db853 100644 --- a/mixer/src/test/java/profiling/ECGroup/Encode.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; diff --git a/mixer/src/test/java/profiling/ECGroup/Mul.java b/mixer/src/test/java/profiling/ECGroup/Mul.java index bb7ecaf..f59bf68 100644 --- a/mixer/src/test/java/profiling/ECGroup/Mul.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.security.spec.InvalidKeySpecException; diff --git a/mixer/src/test/java/profiling/ECGroup/Negate.java b/mixer/src/test/java/profiling/ECGroup/Negate.java index 0c2d9d7..91ee6e4 100644 --- a/mixer/src/test/java/profiling/ECGroup/Negate.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -4,10 +4,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; diff --git a/mixer/src/test/java/profiling/Rerandomize.java b/mixer/src/test/java/profiling/Rerandomize.java index 495c7ca..8e9ddb4 100644 --- a/mixer/src/test/java/profiling/Rerandomize.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -1,21 +1,13 @@ package profiling; -import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import mixer.Utiles; -import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index 356e69a..dcacd0d 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -4,20 +4,16 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import mixer.Utiles; import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.DigestOracle; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; import prover.Prover; -import qilin.primitives.RandomOracle; -import qilin.primitives.concrete.DigestOracle; -import qilin.primitives.concrete.ECElGamal; -import qilin.primitives.concrete.ECGroup; - import java.math.BigInteger; import java.util.Random; diff --git a/settings.gradle.orig b/settings.gradle.orig new file mode 100644 index 0000000..a5cec3b --- /dev/null +++ b/settings.gradle.orig @@ -0,0 +1,11 @@ +include 'meerkat-common' +include 'voting-booth' +include 'bulletin-board-server' +include 'polling-station' +include 'restful-api-common' +<<<<<<< HEAD +include 'mixer' +======= +include 'bulletin-board-client' + +>>>>>>> e8e511d9ce636a127bb33d70ebfd9b2f230c6e1d From f5410bedf4b0f68e602d86ab754cdb016f52c399 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Tue, 5 Apr 2016 11:51:01 +0300 Subject: [PATCH 23/66] Typo fixes --- mixer/src/test/java/mixer/CreateTestVector.java | 4 ++-- .../mixer/{MixingText.java => MixingTest.java} | 6 +++--- mixer/src/test/java/mixer/RerandomizeTest.java | 8 ++++---- .../test/java/mixer/{Utiles.java => Utils.java} | 2 +- .../test/java/mixer/ZeroKnowledgeProofTest.java | 14 +++++++------- .../src/test/java/profiling/BigInteger/AddSub.java | 4 ++-- .../profiling/BigInteger/GenerateRandomness.java | 4 ++-- .../src/test/java/profiling/BigInteger/Modulo.java | 4 ++-- mixer/src/test/java/profiling/BigInteger/Mul.java | 4 ++-- .../java/profiling/Convert/ByteString2ECPoint.java | 6 +++--- ...omizableEncryptedMessage2ElGamalCiphertext.java | 6 +++--- mixer/src/test/java/profiling/ECGroup/Add.java | 4 ++-- mixer/src/test/java/profiling/ECGroup/Encode.java | 4 ++-- mixer/src/test/java/profiling/ECGroup/Mul.java | 4 ++-- mixer/src/test/java/profiling/ECGroup/Negate.java | 4 ++-- mixer/src/test/java/profiling/Rerandomize.java | 6 +++--- .../test/java/profiling/ZeroKnowledgeProof.java | 6 +++--- 17 files changed, 45 insertions(+), 45 deletions(-) rename mixer/src/test/java/mixer/{MixingText.java => MixingTest.java} (93%) rename mixer/src/test/java/mixer/{Utiles.java => Utils.java} (99%) diff --git a/mixer/src/test/java/mixer/CreateTestVector.java b/mixer/src/test/java/mixer/CreateTestVector.java index 591b397..ed43995 100644 --- a/mixer/src/test/java/mixer/CreateTestVector.java +++ b/mixer/src/test/java/mixer/CreateTestVector.java @@ -43,7 +43,7 @@ public class CreateTestVector { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); randomMixer = new Random(); randomProver = new Random(); randomOracle = new DigestOracle(); @@ -61,7 +61,7 @@ public class CreateTestVector { List result = new ArrayList(); Voting.PlaintextBallot msg; for (int i = 0; i < n ; i++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); } return result; diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingTest.java similarity index 93% rename from mixer/src/test/java/mixer/MixingText.java rename to mixer/src/test/java/mixer/MixingTest.java index dc003be..63f6426 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingTest.java @@ -24,7 +24,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -public class MixingText { +public class MixingTest { ECElGamalEncryption encryptor; ECGroup group; @@ -43,7 +43,7 @@ public class MixingText { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); randomMixer = new Random(); randomProver = new Random(); randomOracle = new DigestOracle(); @@ -61,7 +61,7 @@ public class MixingText { List result = new ArrayList(); Voting.PlaintextBallot msg; for (int i = 0; i < n ; i++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); } return result; diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/mixer/RerandomizeTest.java index 66b0343..034e311 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/mixer/RerandomizeTest.java @@ -35,7 +35,7 @@ public class RerandomizeTest { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); RandomOracle randomOracle = new DigestOracle(); @@ -48,7 +48,7 @@ public class RerandomizeTest { } public void oneRerandomizeTest() throws InvalidProtocolBufferException { - Voting.PlaintextBallot msg = Utiles.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Voting.PlaintextBallot msg = Utils.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. Crypto.EncryptionRandomness r = enc.generateRandomness(rand); @@ -56,8 +56,8 @@ public class RerandomizeTest { Crypto.RerandomizableEncryptedMessage e = enc.encrypt(msg, enc.generateRandomness(rand)); Crypto.RerandomizableEncryptedMessage eNew = enc.rerandomize(e, r); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg)); ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e); ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew); diff --git a/mixer/src/test/java/mixer/Utiles.java b/mixer/src/test/java/mixer/Utils.java similarity index 99% rename from mixer/src/test/java/mixer/Utiles.java rename to mixer/src/test/java/mixer/Utils.java index 0bb0e36..78e789e 100644 --- a/mixer/src/test/java/mixer/Utiles.java +++ b/mixer/src/test/java/mixer/Utils.java @@ -26,7 +26,7 @@ import java.util.Random; /** * Created by Tzlil on 1/1/2016. */ -public class Utiles { +public class Utils { public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java index 4e9b404..413fbc8 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -40,7 +40,7 @@ public class ZeroKnowledgeProofTest { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); RandomOracle randomOracle = new DigestOracle(); @@ -53,8 +53,8 @@ public class ZeroKnowledgeProofTest { } public void oneZKPTest() throws InvalidProtocolBufferException { - Voting.PlaintextBallot msg1 = Utiles.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - Voting.PlaintextBallot msg2 = Utiles.genRandomBallot(2,3,16); + Voting.PlaintextBallot msg1 = Utils.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Voting.PlaintextBallot msg2 = Utils.genRandomBallot(2,3,16); Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand); Crypto.EncryptionRandomness r2 = enc.generateRandomness(rand); @@ -63,10 +63,10 @@ public class ZeroKnowledgeProofTest { Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1); Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e1New).equals(msg1)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); - assert (Utiles.decrypt(Voting.PlaintextBallot.class, key, group, e2New).equals(msg2)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1New).equals(msg1)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); + assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2New).equals(msg2)); ECPoint g = group.getGenerator(); ECPoint h = enc.getElGamalPK().getPK(); diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java index b7cca3f..19474f7 100644 --- a/mixer/src/test/java/profiling/BigInteger/AddSub.java +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -28,7 +28,7 @@ public class AddSub { ECGroup group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); ECElGamal.SK key = new ECElGamal.SK(group, sk); - ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ECElGamalEncryption enc = new ECElGamalEncryption(); enc.init(serializedPk); diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java index 8711ab4..e003dea 100644 --- a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -25,7 +25,7 @@ public class GenerateRandomness { BigInteger sk = ECElGamal.generateSecretKey(group, rand); ECElGamal.SK key = new ECElGamal.SK(group, sk); - ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java index 8d2a6b9..9443347 100644 --- a/mixer/src/test/java/profiling/BigInteger/Modulo.java +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -27,7 +27,7 @@ public class Modulo { BigInteger sk = ECElGamal.generateSecretKey(group, rand); ECElGamal.SK key = new ECElGamal.SK(group, sk); - ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ECElGamalEncryption enc = new ECElGamalEncryption(); enc.init(serializedPk); for (int i =0 ; i < tests ; i++){ diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java index b7d8730..dfb8090 100644 --- a/mixer/src/test/java/profiling/BigInteger/Mul.java +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -28,7 +28,7 @@ public class Mul { ECGroup group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); ECElGamal.SK key = new ECElGamal.SK(group, sk); - ConcreteCrypto.ElGamalPublicKey serializedPk = Utiles.serializePk(group, key); + ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ECElGamalEncryption enc = new ECElGamalEncryption(); enc.init(serializedPk); diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index 931e0e3..92b0c3f 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -5,7 +5,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Voting; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -30,7 +30,7 @@ public class ByteString2ECPoint { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); tests = 1024 * 19; @@ -39,7 +39,7 @@ public class ByteString2ECPoint { Voting.PlaintextBallot msg; for (int i = 0; i < tests; i ++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); encryptedMessage[i] = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext (enc.encrypt(msg, enc.generateRandomness(rand))); diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java index 18625d0..3473430 100644 --- a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -29,7 +29,7 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); tests = 1024 * 18; @@ -38,7 +38,7 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext { Voting.PlaintextBallot msg; for (int i = 0; i < tests; i ++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); } diff --git a/mixer/src/test/java/profiling/ECGroup/Add.java b/mixer/src/test/java/profiling/ECGroup/Add.java index ceadc43..a1cbdfb 100644 --- a/mixer/src/test/java/profiling/ECGroup/Add.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -29,7 +29,7 @@ public class Add { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); // generate n; int sqrtn = 128; n = sqrtn*sqrtn; diff --git a/mixer/src/test/java/profiling/ECGroup/Encode.java b/mixer/src/test/java/profiling/ECGroup/Encode.java index 57db853..d9577d7 100644 --- a/mixer/src/test/java/profiling/ECGroup/Encode.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -29,7 +29,7 @@ public class Encode { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); // generate n; int sqrtn = 128; n = sqrtn*sqrtn; diff --git a/mixer/src/test/java/profiling/ECGroup/Mul.java b/mixer/src/test/java/profiling/ECGroup/Mul.java index f59bf68..2a5573a 100644 --- a/mixer/src/test/java/profiling/ECGroup/Mul.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -30,7 +30,7 @@ public class Mul { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); // generate n int sqrtn = 128; n = sqrtn*sqrtn; diff --git a/mixer/src/test/java/profiling/ECGroup/Negate.java b/mixer/src/test/java/profiling/ECGroup/Negate.java index 91ee6e4..f5b6e15 100644 --- a/mixer/src/test/java/profiling/ECGroup/Negate.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -28,7 +28,7 @@ public class Negate { random = new Random(); group = new ECGroup("secp256k1"); encryptor = new ECElGamalEncryption(); - encryptor.init(Utiles.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); + encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); // generate n; int sqrtn = 128; n = sqrtn*sqrtn; diff --git a/mixer/src/test/java/profiling/Rerandomize.java b/mixer/src/test/java/profiling/Rerandomize.java index 8e9ddb4..ea900b5 100644 --- a/mixer/src/test/java/profiling/Rerandomize.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utiles; +import mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; @@ -31,7 +31,7 @@ public class Rerandomize { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); int LogVotes = 10; @@ -43,7 +43,7 @@ public class Rerandomize { Voting.PlaintextBallot msg; for (int i = 0; i < n ; i ++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); randomnesses[i] = enc.generateRandomness(rand); encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); } diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index dcacd0d..fe1d407 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -7,7 +7,7 @@ import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utiles; +import mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; @@ -39,7 +39,7 @@ public class ZeroKnowledgeProof { group = new ECGroup("secp256k1"); BigInteger sk = ECElGamal.generateSecretKey(group, rand); key = new ECElGamal.SK(group, sk); - serializedPk = Utiles.serializePk(group, key); + serializedPk = Utils.serializePk(group, key); enc = new ECElGamalEncryption(); enc.init(serializedPk); RandomOracle randomOracle = new DigestOracle(); @@ -55,7 +55,7 @@ public class ZeroKnowledgeProof { for (int i = 0; i < n*2 ; i ++){ - msg = Utiles.genRandomBallot(2,3,16); + msg = Utils.genRandomBallot(2,3,16); randomnesses[i] = enc.generateRandomness(rand); encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand)); reencryptedMessage[i] = enc.rerandomize(encryptedMessage[i], randomnesses[i]); From b4e50408140f25393cce48546667a4d310960b53 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 17 Apr 2016 09:08:21 +0300 Subject: [PATCH 24/66] comments --- mixer/src/main/java/main/BatchConverter.java | 91 ------ mixer/src/main/java/main/BatchHandler.java | 77 ----- mixer/src/main/java/main/MainMixing.java | 95 ------ .../java/meerkat/mixer/main/BatchHandler.java | 7 + .../java/meerkat/mixer/main/MainMixing.java | 7 + .../java/meerkat/mixer/mixing/MixNetwork.java | 7 + .../main/java/meerkat/mixer/mixing/Mixer.java | 7 + .../meerkat/mixer/mixing/MixerOutput.java | 7 + .../mixer/mixing/RandomPermutation.java | 7 + .../java/meerkat/mixer/mixing/Switch.java | 7 + .../necessary/AsyncBulletinBoardClient.java | 7 + .../mixer/necessary/BulletinBoardClient.java | 7 + .../mixer/necessary/CompleteBatch.java | 7 + .../mixer/prover/ElGamalProofOrganizer.java | 7 + .../java/meerkat/mixer/prover/Prover.java | 7 + .../java/meerkat/mixer/verifier/Verifier.java | 7 + .../meerkat/mixer/verifier/VerifyTable.java | 7 + .../verifier/ZeroKnowledgeOrProofParser.java | 7 + mixer/src/main/java/mixer/MixNetwork.java | 175 ---------- mixer/src/main/java/mixer/Mixer.java | 150 --------- mixer/src/main/java/mixer/MixerOutput.java | 106 ------ .../main/java/mixer/RandomPermutation.java | 32 -- mixer/src/main/java/mixer/Switch.java | 28 -- .../necessary/AsyncBulletinBoardClient.java | 78 ----- .../java/necessary/BulletinBoardClient.java | 63 ---- .../main/java/necessary/CompleteBatch.java | 68 ---- .../java/prover/ElGamalProofOrganizer.java | 303 ------------------ mixer/src/main/java/prover/Prover.java | 215 ------------- mixer/src/main/java/verifier/Verifier.java | 121 ------- mixer/src/main/java/verifier/VerifyTable.java | 88 ----- .../verifier/ZeroKnowledgeOrProofParser.java | 69 ---- .../{ => meerkat}/mixer/CreateTestVector.java | 5 +- .../{ => meerkat}/mixer/MixNetworkTest.java | 2 +- .../java/{ => meerkat}/mixer/MixingTest.java | 2 +- .../{ => meerkat}/mixer/RerandomizeTest.java | 2 +- .../mixer/SimpleRerandomizeTest.java | 2 +- .../test/java/{ => meerkat}/mixer/Utils.java | 2 +- .../mixer/ZeroKnowledgeProofTest.java | 2 +- 38 files changed, 115 insertions(+), 1766 deletions(-) delete mode 100644 mixer/src/main/java/main/BatchConverter.java delete mode 100644 mixer/src/main/java/main/BatchHandler.java delete mode 100644 mixer/src/main/java/main/MainMixing.java create mode 100644 mixer/src/main/java/meerkat/mixer/main/BatchHandler.java create mode 100644 mixer/src/main/java/meerkat/mixer/main/MainMixing.java create mode 100644 mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java create mode 100644 mixer/src/main/java/meerkat/mixer/mixing/Mixer.java create mode 100644 mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java create mode 100644 mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java create mode 100644 mixer/src/main/java/meerkat/mixer/mixing/Switch.java create mode 100644 mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java create mode 100644 mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java create mode 100644 mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java create mode 100644 mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java create mode 100644 mixer/src/main/java/meerkat/mixer/prover/Prover.java create mode 100644 mixer/src/main/java/meerkat/mixer/verifier/Verifier.java create mode 100644 mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java create mode 100644 mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java delete mode 100644 mixer/src/main/java/mixer/MixNetwork.java delete mode 100644 mixer/src/main/java/mixer/Mixer.java delete mode 100644 mixer/src/main/java/mixer/MixerOutput.java delete mode 100644 mixer/src/main/java/mixer/RandomPermutation.java delete mode 100644 mixer/src/main/java/mixer/Switch.java delete mode 100644 mixer/src/main/java/necessary/AsyncBulletinBoardClient.java delete mode 100644 mixer/src/main/java/necessary/BulletinBoardClient.java delete mode 100644 mixer/src/main/java/necessary/CompleteBatch.java delete mode 100644 mixer/src/main/java/prover/ElGamalProofOrganizer.java delete mode 100644 mixer/src/main/java/prover/Prover.java delete mode 100644 mixer/src/main/java/verifier/Verifier.java delete mode 100644 mixer/src/main/java/verifier/VerifyTable.java delete mode 100644 mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java rename mixer/src/test/java/{ => meerkat}/mixer/CreateTestVector.java (97%) rename mixer/src/test/java/{ => meerkat}/mixer/MixNetworkTest.java (97%) rename mixer/src/test/java/{ => meerkat}/mixer/MixingTest.java (99%) rename mixer/src/test/java/{ => meerkat}/mixer/RerandomizeTest.java (99%) rename mixer/src/test/java/{ => meerkat}/mixer/SimpleRerandomizeTest.java (99%) rename mixer/src/test/java/{ => meerkat}/mixer/Utils.java (99%) rename mixer/src/test/java/{ => meerkat}/mixer/ZeroKnowledgeProofTest.java (99%) diff --git a/mixer/src/main/java/main/BatchConverter.java b/mixer/src/main/java/main/BatchConverter.java deleted file mode 100644 index c4e3404..0000000 --- a/mixer/src/main/java/main/BatchConverter.java +++ /dev/null @@ -1,91 +0,0 @@ -package main; - -import com.google.protobuf.ByteString; -import meerkat.crypto.mixnet.MixerOutput; -import meerkat.protobuf.BulletinBoardAPI; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Tzlil on 12/17/2015. - */ - -public class BatchConverter { - - private final int n,layers; - public BatchConverter(int n,int layers){ - this.n = n; - this.layers = layers; - } - - private ByteString Integer2ByteString(int a){ - return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); - } - - private int ByteString2Integer(ByteString bs) { - return Integer.valueOf(bs.toString()); - } - - public List MixerOutput2BatchData(MixerOutput mixerOutput) { - - List result = new ArrayList(); - - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(Integer2ByteString(n)) - .build()); - - for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) { - for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(zkp.toByteString()) - .build()); - } - } - for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.getEncryptedMessages()) { - for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { - result.add(BulletinBoardAPI.BatchData.newBuilder() - .setData(encryption.toByteString()) - .build()); - } - } - return result; - } - - public MixerOutput BatchDataList2MixerOutput - (List batchDataList) throws Exception { - - if (n != ByteString2Integer(batchDataList.remove(0).getData())){ - throw new Exception(); - } - - int nDiv2 = n >>1; - Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; - for (int layer = 0; layer < layers; layer++) - { - for (int proofIndex = 0 ; proofIndex < nDiv2 ; proofIndex ++) - { - proofs[layer][proofIndex] = Mixing.ZeroKnowledgeProof.parseFrom(batchDataList.remove(0).getData()); - } - } - - Crypto.RerandomizableEncryptedMessage[][] encryptions - = new Crypto.RerandomizableEncryptedMessage[layers + 1][n]; - for (int layer = 0; layer < layers + 1; layer++) - { - for (int encryptionIndex = 0 ; encryptionIndex < n ; encryptionIndex ++) - { - encryptions[layer][encryptionIndex] = Crypto.RerandomizableEncryptedMessage - .parseFrom(batchDataList.remove(0).getData()); - } - } - - return new mixer.MixerOutput(n,layers,proofs,encryptions); - - } - -} - diff --git a/mixer/src/main/java/main/BatchHandler.java b/mixer/src/main/java/main/BatchHandler.java deleted file mode 100644 index 00eb510..0000000 --- a/mixer/src/main/java/main/BatchHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -package main; - -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.crypto.mixnet.MixerOutput; -import meerkat.protobuf.Crypto; -import necessary.AsyncBulletinBoardClient; -import necessary.CompleteBatch; -import verifier.VerifyTable; - -import java.util.Arrays; -import java.util.List; - -/** - * Created by Tzlil on 12/17/2015. - */ -public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback { - - private MixerOutput mixerOutput; - private boolean msgReceived; - private Throwable t; - private CompleteBatch msg; - - private final int n, layers; - private final Mix2ZeroKnowledgeVerifier verifier; - - public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) { - this.mixerOutput = null; - this.n = n; - this.layers = layers; - this.msgReceived = false; - this.t = null; - this.verifier = verifier; - } - - @Override - public void handleCallback(CompleteBatch msg) { - this.msg = msg; - this.msgReceived = true; - } - - @Override - public void handleFailure(Throwable t) { - this.t = t; - this.msgReceived = true; - } - - - public boolean isMsgReceived() { - return msgReceived; - } - - private void convertMessage() throws Exception { - BatchConverter batchConverter = new BatchConverter(n,layers); - mixerOutput = batchConverter.BatchDataList2MixerOutput(msg.getBatchDataList()); - } - - public boolean verifyTable() throws Exception { - if (mixerOutput == null) { - convertMessage(); - } - return VerifyTable.verifyTable(verifier, n, mixerOutput); - } - - public List getInputForMixer() throws Throwable { - if (t != null) { - throw t; - } - if (mixerOutput == null) { - convertMessage(); - if (!VerifyTable.verifyTable(verifier, n, mixerOutput)) { - throw new Exception("in valid table"); - } - } - return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1 - } -} - diff --git a/mixer/src/main/java/main/MainMixing.java b/mixer/src/main/java/main/MainMixing.java deleted file mode 100644 index 2b6c09a..0000000 --- a/mixer/src/main/java/main/MainMixing.java +++ /dev/null @@ -1,95 +0,0 @@ -package main; - -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.crypto.mixnet.Mixer; -import meerkat.crypto.mixnet.MixerOutput; -import meerkat.protobuf.BulletinBoardAPI; -import meerkat.protobuf.Crypto; -import necessary.AsyncBulletinBoardClient; - - -import java.util.ArrayList; -import java.util.List; - - -/** - * Created by Tzlil on 12/17/2015. - */ -public class MainMixing { - - private final Mixer mixer; - private final Mix2ZeroKnowledgeVerifier verifier; - private final int n, layers; - private final AsyncBulletinBoardClient asyncBulletinBoardClient; - private final byte[] id; - private final int mixerOrder; - - - public MainMixing(Mixer mixer, int mixerOrder, Mix2ZeroKnowledgeVerifier verifier, int n - , AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) { - this.mixer = mixer; - this.mixerOrder = mixerOrder; - this.verifier = verifier; - this.n = n; - this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 - this.asyncBulletinBoardClient = asyncBulletinBoardClient; - this.id = id; - } - - public void main(List prevBatchIds, int batchId, AsyncBulletinBoardClient.ClientCallback callback) throws Throwable { - - List mixerInput; - - List batchHandlers = new ArrayList(prevBatchIds.size()); - BatchHandler currentBatchHandler; - for (Integer prevBatchId : prevBatchIds) { - currentBatchHandler = new BatchHandler(n, layers,verifier); - asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); - batchHandlers.add(currentBatchHandler); - } - - // ToDo : assert table continues - // ToDo : assert signature validity - - boolean allDone = false; - while (!allDone) { - try { - Thread.sleep(30); - } catch (InterruptedException e) { - // do nothing - } - // check all handlers messages were received - allDone = true; - for (BatchHandler batchHandler : batchHandlers) { - allDone &= batchHandler.isMsgReceived(); - } - } - - // assert all handlers succeeded - for (BatchHandler batchHandler : batchHandlers) { - if(!batchHandler.verifyTable()){ - throw new Exception("invalid input"); - } - } - - BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); - mixerInput = lastBatchHandler.getInputForMixer(); - - MixerOutput mixerOutput = mixer.mix(mixerInput); - updateBB(mixerOutput, batchId, callback); - - } - - - private void updateBB(MixerOutput mixerOutput - , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { - - BatchConverter batchConverter = new BatchConverter(n,layers); - List batchDataList = batchConverter.MixerOutput2BatchData(mixerOutput); - asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); - } - - - - -} diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java new file mode 100644 index 0000000..dee9129 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java @@ -0,0 +1,7 @@ +package meerkat.mixer.main; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class BatchHandler { +} diff --git a/mixer/src/main/java/meerkat/mixer/main/MainMixing.java b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java new file mode 100644 index 0000000..27b6fca --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java @@ -0,0 +1,7 @@ +package meerkat.mixer.main; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class MainMixing { +} diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java new file mode 100644 index 0000000..71770ce --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java @@ -0,0 +1,7 @@ +package meerkat.mixer.mixing; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class MixNetwork { +} diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java new file mode 100644 index 0000000..c405784 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java @@ -0,0 +1,7 @@ +package meerkat.mixer.mixing; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class Mixer { +} diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java new file mode 100644 index 0000000..dbeac75 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java @@ -0,0 +1,7 @@ +package meerkat.mixer.mixing; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class MixerOutput { +} diff --git a/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java new file mode 100644 index 0000000..9202403 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java @@ -0,0 +1,7 @@ +package meerkat.mixer.mixing; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class RandomPermutation { +} diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Switch.java b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java new file mode 100644 index 0000000..0d9c17e --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java @@ -0,0 +1,7 @@ +package meerkat.mixer.mixing; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class Switch { +} diff --git a/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java new file mode 100644 index 0000000..410bf54 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java @@ -0,0 +1,7 @@ +package meerkat.mixer.necessary; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class AsyncBulletinBoardClient { +} diff --git a/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java new file mode 100644 index 0000000..a4e0a0a --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java @@ -0,0 +1,7 @@ +package meerkat.mixer.necessary; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class BulletinBoardClient { +} diff --git a/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java new file mode 100644 index 0000000..b8067e5 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java @@ -0,0 +1,7 @@ +package meerkat.mixer.necessary; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class CompleteBatch { +} diff --git a/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java new file mode 100644 index 0000000..1d2272b --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java @@ -0,0 +1,7 @@ +package meerkat.mixer.prover; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class ElGamalProofOrganizer { +} diff --git a/mixer/src/main/java/meerkat/mixer/prover/Prover.java b/mixer/src/main/java/meerkat/mixer/prover/Prover.java new file mode 100644 index 0000000..9bda892 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/prover/Prover.java @@ -0,0 +1,7 @@ +package meerkat.mixer.prover; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class Prover { +} diff --git a/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java new file mode 100644 index 0000000..0b19faa --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java @@ -0,0 +1,7 @@ +package meerkat.mixer.verifier; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class Verifier { +} diff --git a/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java new file mode 100644 index 0000000..1158e2e --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java @@ -0,0 +1,7 @@ +package meerkat.mixer.verifier; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class VerifyTable { +} diff --git a/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java new file mode 100644 index 0000000..44fe45d --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java @@ -0,0 +1,7 @@ +package meerkat.mixer.verifier; + +/** + * Created by Tzlil on 4/16/2016. + */ +public class ZeroKnowledgeOrProofParser { +} diff --git a/mixer/src/main/java/mixer/MixNetwork.java b/mixer/src/main/java/mixer/MixNetwork.java deleted file mode 100644 index 833ef73..0000000 --- a/mixer/src/main/java/mixer/MixNetwork.java +++ /dev/null @@ -1,175 +0,0 @@ -package mixer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.Random; - -/** - * Created by Tzlil on 12/15/2015. - */ -public class MixNetwork { - - private final Switch[][] switches; - - public MixNetwork(RandomPermutation randomPermutation) - { - int[] permutation = randomPermutation.permutation; - int n = permutation.length; - assert ((n & n-1) == 0); //n == 2^k - int layers = (int)(2*Math.log(n)/Math.log(2)) - 1; - - int[] pi, piL, piR; - Queue permutationsQueue = new ArrayBlockingQueue(n); - Graph graph; - int iDiv2; - int nDiv2 = n >> 1; - switches = new Switch[layers][nDiv2]; - int index1,index2; - - permutationsQueue.add(permutation); - for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size - { - iDiv2 = i >> 1; - for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation start index - { - pi = permutationsQueue.remove(); - graph = new Graph(pi); - piL = new int[iDiv2]; - piR = new int[iDiv2]; - for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j - { - index1 = k + (j << 1); - index2 = index1 + iDiv2; - switches[layers - layer - 1][k + j] = new Switch(index1,index2,layers - layer - 1,graph.getSwitchValue(k, true)); - switches[layer][k + j] = new Switch(index1,index2,layer,graph.getSwitchValue(k, false)); - - if (!switches[layers - layer - 1][k + j].value) { - piL[k] = pi[k] % iDiv2; - piR[k] = pi[k + iDiv2] % iDiv2; - } else { - piL[k] = pi[k + iDiv2] % iDiv2; - piR[k] = pi[k] % iDiv2; - } - } - permutationsQueue.add(piL); - permutationsQueue.add(piR); - } - } - } - - public Switch[] getSwitchesByLayer(int layer) - { - return switches[layer]; - } - - private class Graph { - private int n; - private int nDiv2; - private Node[][] nodes; - protected Graph(int[] permutation){ - n = permutation.length; // n = 2^k - nDiv2 = n >> 1; - createNodes(); - createEdges(permutation); - setSwitches(); - } - - // provide an access to algorithm result - // index must be less then n/2 - protected boolean getSwitchValue(int index,boolean up) - { - return up ? nodes[0][index].value : nodes[1][index].value; - } - - // create two lines of nodes size n/2 each - // the value of the i th node is (i,i+n/2) if i < n /2 (first line) - // otherwise its value is (i - n/2 , i) (second line) - private void createNodes() - { - nodes = new Node[2][nDiv2]; - for (int i = 0; i < nDiv2; i++) - { - nodes[0][i] = new Node(); - nodes[1][i] = new Node(); - } - } - - // create an edge between each pair of nodes i,j from different lines (i index of the first line) - // if exists k in i th node's value and t in j th node's value - // s.t permutation[k] == t - // the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) - // Note: in purpose to avoid edge cases, each node has exactly two edges - private void createEdges(int[] permutation) - { - int j; - for (int i = 0; i < nDiv2; i++) - { - j = permutation[i] % nDiv2; - nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i] >= nDiv2))); - nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i] >= nDiv2))); - - j = permutation[i + nDiv2] % nDiv2; - nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i + nDiv2] < nDiv2))); - nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i + nDiv2] < nDiv2))); - } - } - - // set switch's value (on/off) for each switch (node) - // s.t if nodes i,j connected by edge e, i th switch's value - // must be equal to j's if e is broken or not equal if e is not broken - private void setSwitches() - { - Node node; - boolean v; - Edge e0,e1; - // iterate over first line of nodes - for (int i = 0; i < nDiv2; i++) - { - node = nodes[0][i]; - if (node.set) - continue; - //select default value for first node in connected component - v = false; - // set value to all reachable nodes from node - while (true) - { - node.set = true; - node.value = v; - e0 = node.edges.get(0); e1 = node.edges.get(1); - if (e0.neighbor.set && e1.neighbor.set) - break; - v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; - node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; - } - } - } - - //inner classes - private class Node - { - public List edges; - private boolean value; - private boolean set; - public Node() - { - edges = new ArrayList(2); - set = false; - } - } - - private class Edge - { - public Node neighbor; - public boolean broken; - public Edge(Node neighbor, boolean broken) - { - this.neighbor = neighbor; - this.broken = broken; - } - } - } - - -} diff --git a/mixer/src/main/java/mixer/Mixer.java b/mixer/src/main/java/mixer/Mixer.java deleted file mode 100644 index ddee9f9..0000000 --- a/mixer/src/main/java/mixer/Mixer.java +++ /dev/null @@ -1,150 +0,0 @@ -package mixer; - -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.Encryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.crypto.mixnet.MixerOutput; -import meerkat.protobuf.Crypto.EncryptionRandomness; -import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage; -import meerkat.protobuf.Mixing.ZeroKnowledgeProof; - -import java.math.BigInteger; -import java.util.List; -import java.util.Random; - -public class Mixer implements meerkat.crypto.mixnet.Mixer { - - protected final Random random; - protected final Mix2ZeroKnowledgeProver prover; - protected final Encryption encryptor; - protected final Mix2ZeroKnowledgeVerifier verifier; - - public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc) { - this.random = rand; - this.prover = prov; - this.encryptor = enc; - this.verifier = null; - } - - public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc,Mix2ZeroKnowledgeVerifier verifier) { - this.random = rand; - this.prover = prov; - this.encryptor = enc; - this.verifier = verifier; - } - - // assert n = 2^k and n > 1 - protected boolean inputBasicCheckSum(int n){ - return n > 1 && ((n & (n - 1)) == 0); - } - protected RerandomizableEncryptedMessage[][] initializeEncryptionTable(int n,int layers,List ciphertexts){ - // set first level of encryption - RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; - for (int j = 0; j < n; j++) { - encryptionTable[0][j] = ciphertexts.get(j); - } - return encryptionTable; - } - - protected EncryptionRandomness[][] generateRandomnessesForRerandomize(int n,int layers){ - EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; - for (int layer = 0; layer < layers; layer++) - { - for (int i = 0; i < n; i++) { - randomnesses[layer][i] = encryptor.generateRandomness(random);; - } - } - return randomnesses; - } - - protected MixNetwork createMixNetwork(int n){ - return new MixNetwork(new RandomPermutation(n,random)); - } - - protected void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable - ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { - Switch[] switchesLayer; - int index1,index2; - RerandomizableEncryptedMessage e1,e2; - EncryptionRandomness r1,r2; - for (int layer = 0; layer < layers; layer++) - { - switchesLayer = mixNetwork.getSwitchesByLayer(layer); - for (Switch sw : switchesLayer) { - index1 = sw.i; - index2 = sw.j; - e1 = encryptionTable[layer][index1]; - e2 = encryptionTable[layer][index2]; - - r1 = randomnesses[layer][index1]; - r2 = randomnesses[layer][index2]; - if (!sw.value) { - encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); - encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); - - } else { - encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); - encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); - } - } - } - } - - protected ZeroKnowledgeProof[][] createZKPTable(int n,int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable - ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { - Switch[] switchesLayer; - int index1,index2; - int switchIndex = 0; - int nDiv2 = n >> 1; - ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; - - - RerandomizableEncryptedMessage e1,e2; - EncryptionRandomness r1,r2; - for (int layer = 0; layer < layers; layer++) - { - switchesLayer = mixNetwork.getSwitchesByLayer(layer); - for (Switch sw : switchesLayer) { - index1 = sw.i; - index2 = sw.j; - e1 = encryptionTable[layer][index1]; - e2 = encryptionTable[layer][index2]; - r1 = randomnesses[layer][index1]; - r2 = randomnesses[layer][index2]; - - proofsTable[layer][switchIndex] = - prover.prove(e1, e2, encryptionTable[layer + 1][index1], - encryptionTable[layer + 1][index2], - sw.value, sw.i, sw.j, sw.layer, r1, r2); - - switchIndex = (switchIndex + 1) % nDiv2; - } - } - return proofsTable; - } - - public MixerOutput mix(List ciphertexts) throws InvalidProtocolBufferException { - - int n = ciphertexts.size(); - - if (!inputBasicCheckSum(n)) - return null; - - int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1 - RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts); - EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers); - MixNetwork mixNetwork = createMixNetwork(n); - - BigInteger time = BigInteger.valueOf(System.currentTimeMillis()); - rerandomize(layers,mixNetwork,encryptionTable,randomnesses); - System.out.println("re enc time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); - - time = BigInteger.valueOf(System.currentTimeMillis()); - ZeroKnowledgeProof[][] proofsTable = createZKPTable(n,layers,mixNetwork,encryptionTable,randomnesses); - System.out.println("zkp time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time)); - - return new mixer.MixerOutput(n,layers,proofsTable, encryptionTable); - } - -} \ No newline at end of file diff --git a/mixer/src/main/java/mixer/MixerOutput.java b/mixer/src/main/java/mixer/MixerOutput.java deleted file mode 100644 index c8efda6..0000000 --- a/mixer/src/main/java/mixer/MixerOutput.java +++ /dev/null @@ -1,106 +0,0 @@ -package mixer; - -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - - -/** - * Created by Tzlil on 1/18/2016. - */ -public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ - private final Mixing.ZeroKnowledgeProof[][] proofs; - private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; - private final int n; - private final int layers; - - public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { - this.proofs = proofs; - this.encryptedMessages = encryptedMessages; - this.n = n; - this.layers = layers; - } - - public MixerOutput(meerkat.crypto.mixnet.MixerOutput mixerOutput) { - this.proofs = mixerOutput.getProofs(); - this.encryptedMessages = mixerOutput.getEncryptedMessages(); - this.n = mixerOutput.getN(); - this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1; - } - - - @Override - public Mixing.ZeroKnowledgeProof[][] getProofs() { - return proofs; - } - - @Override - public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() { - return encryptedMessages; - } - - @Override - public int getN() { - return n; - } - - public void outToFile(String dir) throws IOException { - - (new File(dir)).mkdirs(); - //create files - String proofsDir = dir + "/Proofs"; - String encDir = dir + "/EncryptedMessages"; - (new File(proofsDir)).mkdir(); - (new File(encDir)).mkdir(); - for (int layer = 0; layer < layers; layer++){ - (new File(proofsDir +"/layer" + layer )).mkdir(); - (new File(encDir +"/layer" + layer )).mkdir(); - } - (new File(encDir +"/input")).mkdir(); - - - for (int layer = 0; layer < layers; layer++){ - for(int i = 0; i < proofs[layer].length; i ++){ - writeProofToFile(proofsDir,proofs[layer][i]); - } - } - - for (int layer = 0; layer <= layers; layer++){ - for(int i = 0; i < encryptedMessages[layer].length; i ++){ - writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]); - } - } - } - - private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException { - Mixing.ZeroKnowledgeProof.Location location = proof.getLocation(); - int layer = location.getLayer(); - int i = location.getI(); - int j = location.getJ(); - String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j; - - File file = new File(fileName); - file.createNewFile(); - FileOutputStream fos = new FileOutputStream(file); - fos.write(proof.toByteArray()); - fos.close(); - } - - private void writeEncToFile(String encDir,int layer,int i, Crypto.RerandomizableEncryptedMessage enc) throws IOException { - - String fileName; - if(layer >= 0) - fileName = encDir+"/layer" + layer +"/" + i; - else - fileName = encDir+"/input/" + i; - - File file = new File(fileName); - file.createNewFile(); - FileOutputStream fos = new FileOutputStream(file); - fos.write(enc.toByteArray()); - fos.close(); - } -} diff --git a/mixer/src/main/java/mixer/RandomPermutation.java b/mixer/src/main/java/mixer/RandomPermutation.java deleted file mode 100644 index 900761b..0000000 --- a/mixer/src/main/java/mixer/RandomPermutation.java +++ /dev/null @@ -1,32 +0,0 @@ -package mixer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -/** - * Created by Tzlil on 12/17/2015. - */ -class RandomPermutation { - - protected final int[] permutation; - - protected RandomPermutation(int n,Random random) - { - List numbers= new ArrayList(n); - for (int i = 0; i < n; i++) - { - numbers.add(i); - } - - int[] result = new int[n]; - int index; - for (int i = 0; i < n; i++) - { - index = random.nextInt(n - i); - result[i] = numbers.get(index); - numbers.remove(index); - } - permutation = result; - } -} diff --git a/mixer/src/main/java/mixer/Switch.java b/mixer/src/main/java/mixer/Switch.java deleted file mode 100644 index a7401ff..0000000 --- a/mixer/src/main/java/mixer/Switch.java +++ /dev/null @@ -1,28 +0,0 @@ -package mixer; - -/** - * Created by Tzlil on 12/15/2015. - */ -public class Switch{ - - public final int i, j, layer; - public final boolean value; - - public Switch(int i, int j, int layer, boolean value) { - this.i = i; - this.j = j; - this.layer = layer; - this.value = value; - } - - - @Override - public String toString() { - return "Switch{" + - "i=" + i + - ", j=" + j + - ", layer=" + layer + - ", value=" + value + - '}'; - } -} diff --git a/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java deleted file mode 100644 index 6dcc1f1..0000000 --- a/mixer/src/main/java/necessary/AsyncBulletinBoardClient.java +++ /dev/null @@ -1,78 +0,0 @@ -package necessary; - -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 14-Dec-15. - */ -public interface AsyncBulletinBoardClient extends BulletinBoardClient { - - public interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - - public interface MessageHandler { - void handleNewMessages(List messageList); - } - - /** - * Post a message to the bulletin board in an asynchronous manner - * @param msg is the message to be posted - * @param callback is a class containing methods to handle the result of the operation - * @return a unique message ID for the message, that can be later used to retrieve the batch - */ - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); - - /** - * This method allows for sending large messages as a batch to the bulletin board - * @param signerId is the canonical form for the ID of the sender of this batch - * @param batchId is a unique (per signer) ID for this batch - * @param batchDataList is the (canonically ordered) list of data comprising the batch message - * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) - * @param callback is a callback function class for handling results of the operation - * @return a unique message ID for the entire message, that can be later used to retrieve the batch - */ - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); - - /** - * Overloading of the postBatch method in which startPosition is set to the default value 0 - */ - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); - - /** - * Check how "safe" a given message is in an asynchronous manner - * The result of the computation is a rank between 0.0 and 1.0 indicating the fraction of servers containing the message - * @param id is the unique message identifier for retrieval - * @param callback is a callback function class for handling results of the operation - */ - public void getRedundancy(MessageID id, ClientCallback callback); - - /** - * Read all messages posted matching the given filter in an asynchronous manner - * Note that if messages haven't been "fully posted", this might return a different - * set of messages in different calls. However, messages that are fully posted - * are guaranteed to be included. - * @param filterList return only messages that match the filters (null means no filtering). - * @param callback is a callback function class for handling results of the operation - */ - public void readMessages(MessageFilterList filterList, ClientCallback> callback); - - /** - * Read a given batch message from the bulletin board - * @param signerId is the ID of the signer (sender) of the batch message - * @param batchId is the unique (per signer) ID of the batch - * @param callback is a callback class for handling the result of the operation - */ - public void readBatch(byte[] signerId, int batchId, ClientCallback callback); - - /** - * Subscribes to a notifier that will return any new messages on the server that match the given filters - * @param filterList defines the set of filters for message retrieval - * @param messageHandler defines the handler for new messages received - */ - public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); - -} diff --git a/mixer/src/main/java/necessary/BulletinBoardClient.java b/mixer/src/main/java/necessary/BulletinBoardClient.java deleted file mode 100644 index d8f9f28..0000000 --- a/mixer/src/main/java/necessary/BulletinBoardClient.java +++ /dev/null @@ -1,63 +0,0 @@ -package necessary; - -/** - * Created by Tzlil on 12/27/2015. - */ - - import meerkat.comm.CommunicationException; - import meerkat.protobuf.Voting.*; - - import static meerkat.protobuf.BulletinBoardAPI.*; - - import java.util.List; - -/** - * Created by talm on 24/10/15. - */ -public interface BulletinBoardClient { - - interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - - /** - * Initialize the client to use some specified servers - * @param clientParams contains the parameters required for the client setup - */ - void init(BulletinBoardClientParams clientParams); - - /** - * Post a message to the bulletin board in a synchronous manner - * @param msg is the message to be posted - * @return a unique message ID for the message, that can be later used to retrieve the batch - * @throws CommunicationException - */ - MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; - - - - /** - * Check how "safe" a given message is in a synchronous manner - * @param id is the unique message identifier for retrieval - * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) - */ - float getRedundancy(MessageID id); - - /** - * Read all messages posted matching the given filter in a synchronous manner - * Note that if messages haven't been "fully posted", this might return a different - * set of messages in different calls. However, messages that are fully posted - * are guaranteed to be included. - * @param filterList return only messages that match the filters (null means no filtering). - * @return the list of messages - */ - List readMessages(MessageFilterList filterList); - - /** - * Closes all connections, if any. - * This is msgRecived in a synchronous (blocking) way. - */ - void close(); - -} diff --git a/mixer/src/main/java/necessary/CompleteBatch.java b/mixer/src/main/java/necessary/CompleteBatch.java deleted file mode 100644 index d108a7d..0000000 --- a/mixer/src/main/java/necessary/CompleteBatch.java +++ /dev/null @@ -1,68 +0,0 @@ -package necessary; - - - import meerkat.protobuf.BulletinBoardAPI.*; - import meerkat.protobuf.Crypto.*; - - import java.util.LinkedList; - import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 14-Dec-15. - * - * A data structure for holding a complete batch message along with its signature - */ -public class CompleteBatch { - - private BeginBatchMessage beginBatchMessage; - private List batchDataList; - private Signature signature; - - public CompleteBatch() { - batchDataList = new LinkedList(); - } - - public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { - this(); - beginBatchMessage = newBeginBatchMessage; - } - - public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList) { - this(newBeginBatchMessage); - appendBatchData(newDataList); - } - - public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature) { - this(newBeginBatchMessage, newDataList); - signature = newSignature; - } - - public BeginBatchMessage getBeginBatchMessage() { - return beginBatchMessage; - } - - public List getBatchDataList() { - return batchDataList; - } - - public Signature getSignature() { - return signature; - } - - public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { - this.beginBatchMessage = beginBatchMessage; - } - - public void appendBatchData(BatchData newBatchData) { - batchDataList.add(newBatchData); - } - - public void appendBatchData(List newBatchDataList) { - batchDataList.addAll(newBatchDataList); - } - - public void setSignature(Signature newSignature) { - signature = newSignature; - } - -} diff --git a/mixer/src/main/java/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/prover/ElGamalProofOrganizer.java deleted file mode 100644 index d37713b..0000000 --- a/mixer/src/main/java/prover/ElGamalProofOrganizer.java +++ /dev/null @@ -1,303 +0,0 @@ -package prover; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import org.bouncycastle.math.ec.ECPoint; -import org.factcenter.qilin.primitives.concrete.ECGroup; - -/** - * use for organize the input for each ZKP - * - * both prover and verifier implantation are using it - */ -public class ElGamalProofOrganizer { - - private final ECGroup group; - private final ECPoint g; - private final ECPoint h; - private final byte[] gEncoded; - private final byte[] hEncoded; - - /** - * @param group - * @param g - generator of group - * @param h - h = g ^ SecretKey - */ - public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){ - this.group = group; - this.g = g; - this.h = h; - this.gEncoded = group.encode(g); - this.hEncoded = group.encode(h); - } - - public enum OrProofOrder { - first, second, third, fourth - } - - public enum TrueCouple { - left, right, unknown - } - - /** - * can be used by prover only - * - * call to the main overload with flag = true - */ - protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 - , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 - , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException { - - //boolean flag = true; - return createProofInput(in1,in2,out1,out2,r1,r2,switched,true); - } - - /** - * can be used by anyone, e.g verifier - * - * call to the main overload with flag = false - */ - public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 - , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException { - - // flag = false; - return createProofInput(in1,in2,out1,out2,null,null,false,false); - } - - /** - * inner method - * convert each encrypted message to ElGamalCiphertext - * - * @param flag - true if called by prover ( r1,r2,switched are known) - * @return ElGamalProofInput - * @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't - * ElGamalCiphertext - */ - private ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 - , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 - , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag) - throws InvalidProtocolBufferException { - - //convert RerandomizableEncryptedMessage to ElGamalCiphertext - ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1); - ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2); - ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1); - ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2); - - if(flag) { - return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched); - }else { - return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal); - } - } - - - /** - * can be construct by instance of organizer only by calling createProofInput method (all constructors are private) - * - * in construction it use for preparing the input for prove, while avoiding double converting or calculations - * - * use as a container for 4 OrProofInput. - */ - public class ElGamalProofInput { - - private final OrProofInput first; - private final OrProofInput second; - private final OrProofInput third; - private final OrProofInput fourth; - - private ECPoint convert2ECPoint(ByteString bs){ - return group.decode(bs.toByteArray()); - } - - - /** - * @param flag - true if called by prover ( r1,r2,switched are known) - */ - private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 - , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New - , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag){ - - ECPoint e1c1 = convert2ECPoint(e1.getC1()); - ECPoint e1c2 = convert2ECPoint(e1.getC2()); - ECPoint e2c1 = convert2ECPoint(e2.getC1()); - ECPoint e2c2 = convert2ECPoint(e2.getC2()); - ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); - ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); - ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); - ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); - - ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); - ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); - ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); - ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); - - ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); - ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); - ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); - ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); - - - if(!flag){ - - this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); - this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); - this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); - this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); - - }else { - - byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); - byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); - byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); - byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); - byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); - byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); - byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); - byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); - - - if (!switched) { - this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 - , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded - , r1, TrueCouple.left); - this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 - , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded - , r1, TrueCouple.left); - this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 - , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded - , r2, TrueCouple.right); - this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 - , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded - , r2, TrueCouple.right); - } else { - this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 - , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded - , r2, TrueCouple.right); - this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 - , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded - , r1, TrueCouple.right); - this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 - , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded - , r2, TrueCouple.left); - this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 - , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded - , r1, TrueCouple.left); - } - } - } - - - /** - * used by the prover - * call to the main constructor with flag = true - */ - private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 - , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New - , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){ - //flag = true; - this(e1,e2,e1New,e2New,r1,r2,switched,true); - } - - /** - * used by prover - * call to the main constructor with flag = true - */ - private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 - , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ - //flag = false; - this(e1,e2,e1New,e2New,null,null,false,false); - } - - /** - * getter for all 4 OrProofInputs - * - * @param orProofOrder - * @return the required OrProof - */ - public OrProofInput getOrProofInput(OrProofOrder orProofOrder) { - switch (orProofOrder) { - - case first: - return this.first; - case second: - return this.second; - case third: - return this.third; - case fourth: - return this.fourth; - } - return null; - } - } - - - /** - * can't be constructed (all constructors are private) - * - * 4 instances will be constructed for each new ElGamalProofInput - * - * container for all necessary inputs for single OrProof - */ - public class OrProofInput{ - public final ECPoint g1; - public final ECPoint h1; - public final ECPoint g2; - public final ECPoint h2; - public final ECPoint g1Tag; - public final ECPoint h1Tag; - public final ECPoint g2Tag; - public final ECPoint h2Tag; - - // can be access by prover only - protected final byte[] g1Encoded; - protected final byte[] h1Encoded; - protected final byte[] g2Encoded; - protected final byte[] h2Encoded; - protected final byte[] g1TagEncoded; - protected final byte[] h1TagEncoded; - protected final byte[] g2TagEncoded; - protected final byte[] h2TagEncoded; - protected final Crypto.EncryptionRandomness x; - protected final TrueCouple flag; - - /** - * used by prover only - */ - private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag - ,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded - , Crypto.EncryptionRandomness x, TrueCouple flag) { - this.g1 = g; - this.h1 = h1; - this.g2 = h; - this.h2 = h2; - this.g1Tag = g; - this.h1Tag = h1Tag; - this.g2Tag = h; - this.h2Tag = h2Tag; - - this.g1Encoded = gEncoded; - this.h1Encoded = h1Encoded; - this.g2Encoded = hEncoded; - this.h2Encoded = h2Encoded; - this.g1TagEncoded = gEncoded; - this.h1TagEncoded = h1TagEncoded; - this.g2TagEncoded = hEncoded; - this.h2TagEncoded = h2TagEncoded; - - this.x = x; - this.flag = flag; - - } - - /** - * use by verifier - */ - private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) { - this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown); - } - } -} diff --git a/mixer/src/main/java/prover/Prover.java b/mixer/src/main/java/prover/Prover.java deleted file mode 100644 index 90fdb75..0000000 --- a/mixer/src/main/java/prover/Prover.java +++ /dev/null @@ -1,215 +0,0 @@ -package prover; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; -import org.bouncycastle.math.ec.ECPoint; -import org.factcenter.qilin.primitives.RandomOracle; -import org.factcenter.qilin.primitives.concrete.ECGroup; - -import java.math.BigInteger; -import java.util.Random; - - -/** - * implements of Mix2ZeroKnowledgeProver interface - * this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext - */ -public class Prover implements Mix2ZeroKnowledgeProver { - - private final ECGroup group; - private final RandomOracle randomOracle; - private final Random rand; - private final ECElGamalEncryption encryptor; - private final ECPoint g,h; - private final BigInteger groupOrderUpperBound; - private final ElGamalProofOrganizer organizer; - - /** - * @param rand - * @param encryptor - * @param randomOracle - use for Fiat–Shamir heuristic - */ - public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { - - this.rand = rand; - this.encryptor = encryptor; - this.randomOracle = randomOracle; - this.group = this.encryptor.getGroup(); - this.g = group.getGenerator(); - this.h = this.encryptor.getElGamalPK().getPK(); - this.organizer = new ElGamalProofOrganizer(group,g,h); - this.groupOrderUpperBound = group.orderUpperBound(); - } - - /** - * @param in1 - * @param in2 - * @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1) - * @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2) - * @param sw - flag - * @param i - column of in1 and out1 in encryption table - * @param j - column of in2 and out2 in encryption table - * @param layer - row of in1,in2 in encryption table - * @param r1 - * @param r2 - * @return - a valid ZKP that indeed out1,out2 calculated as required - * @throws InvalidProtocolBufferException - */ - public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - boolean sw,int i,int j, int layer, - Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { - Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; - - ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw); - - first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first)); - second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second)); - third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third)); - fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth)); - - Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() - .setI(i) - .setJ(j) - .setLayer(layer) - .build(); - - Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() - .setFirst(first) - .setSecond(second) - .setThird(third) - .setFourth(fourth) - .setLocation(location) - .build(); - return result; - } - - - /** - * Fiat–Shamir heuristic - * @param input - protobuf contains all parameters from the first step of the current prove - * @return randomOracle.hash(input) - */ - private BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { - byte[] arr = input.toByteArray(); - return new BigInteger(1,this.randomOracle.hash(arr,arr.length)); - } - - - /** - * @param orProofInput - * @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2) - * assuming DLog is hard in this.group then that proves x is known for the prover - */ - private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) { - - ECPoint g1 = orProofInput.g1; - ECPoint h1 = orProofInput.h1; - ECPoint g2 = orProofInput.g2; - ECPoint h2 = orProofInput.h2; - - ECPoint g1Tag = orProofInput.g1Tag; - ECPoint h1Tag = orProofInput.h1Tag; - ECPoint g2Tag = orProofInput.g2Tag; - ECPoint h2Tag = orProofInput.h2Tag; - - BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); - BigInteger c1,c2,z,zTag; - ECPoint u,v,uTag,vTag; - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; - - - switch (orProofInput.flag) { - case left: - c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); - zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); - //step 1 - u = group.multiply(g1, r); - v = group.multiply(g2, r); - uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); - vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); - //step 2 - // c1 = (hash(input + step1) + group size - c2)% group size - forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) - .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) - .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) - .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) - .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) - .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) - .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) - .setU(ByteString.copyFrom(group.encode(u))) - .setV(ByteString.copyFrom(group.encode(v))) - .setUTag(ByteString.copyFrom(group.encode(uTag))) - .setVTag(ByteString.copyFrom(group.encode(vTag))) - .build(); - c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); - //step 3 - //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); - break; - case right: - c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); - z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); - //step 1 - uTag = group.multiply(g1Tag, r); - vTag = group.multiply(g2Tag, r); - u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); - v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); - //step 2 - // c1 = (hash(input + step1) + group size - c1)% group size - forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) - .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) - .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) - .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) - .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) - .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) - .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) - .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) - .setU(ByteString.copyFrom(group.encode(u))) - .setV(ByteString.copyFrom(group.encode(v))) - .setUTag(ByteString.copyFrom(group.encode(uTag))) - .setVTag(ByteString.copyFrom(group.encode(vTag))) - .build(); - c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); - //step 3 - //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); - break; - default: - return null; - } - - - return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() - .setG1(forRandomOracle.getG1()) - .setH1(forRandomOracle.getH1()) - .setG2(forRandomOracle.getG2()) - .setH2(forRandomOracle.getH2()) - .setG1Tag(forRandomOracle.getG1()) - .setH1Tag(forRandomOracle.getH1Tag()) - .setG2Tag(forRandomOracle.getG2Tag()) - .setH2Tag(forRandomOracle.getH2Tag()) - .setU(forRandomOracle.getU()) - .setV(forRandomOracle.getV()) - .setUTag(forRandomOracle.getUTag()) - .setVTag(forRandomOracle.getVTag()) - .setC1(ByteString.copyFrom(c1.toByteArray())) - .setC2(ByteString.copyFrom(c2.toByteArray())) - .setZ(ByteString.copyFrom(z.toByteArray())) - .setZTag(ByteString.copyFrom(zTag.toByteArray())) - .build(); - } -} - diff --git a/mixer/src/main/java/verifier/Verifier.java b/mixer/src/main/java/verifier/Verifier.java deleted file mode 100644 index 21c9520..0000000 --- a/mixer/src/main/java/verifier/Verifier.java +++ /dev/null @@ -1,121 +0,0 @@ -package verifier; - -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; -import org.bouncycastle.math.ec.ECPoint; -import prover.ElGamalProofOrganizer; -import org.factcenter.qilin.primitives.RandomOracle; -import org.factcenter.qilin.primitives.concrete.ECGroup; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - - -public class Verifier implements Mix2ZeroKnowledgeVerifier { - - - private final ECGroup group; - private final RandomOracle randomOracle; - private final ECElGamalEncryption encryptor; - private final ECPoint g,h; - private final ElGamalProofOrganizer organizer; - private final ZeroKnowledgeOrProofParser parser; - - public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { - this.encryptor = encryptor; - this.group = encryptor.getGroup(); - this.g = group.getGenerator(); - this.h = encryptor.getElGamalPK().getPK(); - this.randomOracle = randomOracle; - this.organizer = new ElGamalProofOrganizer(group,g,h); - this.parser = new ZeroKnowledgeOrProofParser(group); - } - - public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) { - byte[] arr = input.toByteArray(); - return new BigInteger(1,this.randomOracle.hash(arr,arr.length)); - } - /** - * @return true iff the proof is valid - */ - public boolean verify(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { - ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2); - return verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first), proof.getFirst())&& - verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second), proof.getSecond())&& - verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third), proof.getThird())&& - verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth), proof.getFourth()); - - } - - - - public boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, - Mixing.ZeroKnowledgeProof.OrProof orProof) { - - ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof); - List conditions = createConditionsList(orProofInput,container); - boolean result = true; - for (Condition condition: conditions) { //temporary - if(!condition.test()){ - if (result){ - result = false; - System.out.print("\n\n\n"); - } - System.out.println(condition.errorDescription); - } - } - return result; - } - - - private List createConditionsList(ElGamalProofOrganizer.OrProofInput orProofInput - ,ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container){ - List conditions = new ArrayList(); - conditions.add(new Condition( container.g1,orProofInput.g1,"g1 != g")); - conditions.add(new Condition( container.h1,orProofInput.h1,"h1 != e1New.c1/e1.c1")); - conditions.add(new Condition( container.g2,orProofInput.g2,"g2 != h")); - conditions.add(new Condition( container.h2,orProofInput.h2,"h2 != e1New.c2/e1.c2")); - conditions.add(new Condition( container.g1Tag,orProofInput.g1Tag,"g1Tag != g")); - conditions.add(new Condition( container.h1Tag,orProofInput.h1Tag,"h1Tag != e2New.c1/e2.c1")); - conditions.add(new Condition( container.g2Tag,orProofInput.g2Tag,"g2Tag != h")); - conditions.add(new Condition( container.h2Tag,orProofInput.h2Tag,"h2Tag != e2New.c2/e2.c2")); - conditions.add(new Condition(container.c1.add(container.c2).mod(group.orderUpperBound()), - hash(container.forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()), - "(c1 + c2 ) % group size == hash (imput + step1) % group size")); - conditions.add(new Condition( group.multiply(container.g1, container.z), - group.add(container.u, group.multiply(container.h1,container.c1)),"g1 ^ z != u * ( h1 ^ c1 )")); - conditions.add(new Condition( group.multiply(container.g2, container.z), - group.add(container.v, group.multiply(container.h2,container.c1)),"g2 ^ z != v * ( h2 ^ c1 )")); - conditions.add(new Condition( group.multiply(container.g1Tag, container.zTag), - group.add(container.uTag, group.multiply(container.h1Tag,container.c2)) - ,"g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )")); - conditions.add(new Condition( group.multiply(container.g2Tag, container.zTag), - group.add(container.vTag, group.multiply(container.h2Tag,container.c2)) - ,"g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )")); - return conditions; - } - - private class Condition{ - - T given, expected; - String errorDescription; - - Condition(T given,T expected,String description){ - this.given = given; - this.errorDescription = description; - this.expected = expected; - } - - boolean test(){ - return given.equals(expected); - } - } -} diff --git a/mixer/src/main/java/verifier/VerifyTable.java b/mixer/src/main/java/verifier/VerifyTable.java deleted file mode 100644 index ebf203c..0000000 --- a/mixer/src/main/java/verifier/VerifyTable.java +++ /dev/null @@ -1,88 +0,0 @@ -package verifier; - -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.crypto.mixnet.MixerOutput; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -import java.util.Arrays; - -/** - * Created by Tzlil on 12/30/2015. - */ -public final class VerifyTable { - - public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput) - throws InvalidProtocolBufferException { - int index1,index2,layer; - - //assert n = 2^k - if ( (n &(n-1)) != 0) - throw new IllegalArgumentException("n"); - - int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1; - //initialize locationChecksum table - // use for check BeneshNet validity - boolean[][] locationChecksum = new boolean[layers][n]; - for (boolean[] locationChecksumLayer: locationChecksum) { - Arrays.fill(locationChecksumLayer,false); - } - - Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs(); - Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); - - for (int i = 0; i < zeroKnowledgeProofs.length ; i++){ - for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){ - Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j]; - if(zkp == null){ - int ttt = 1; - ttt++; - } - Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); - index1 = location.getI(); - index2 = location.getJ(); - layer = location.getLayer(); - - // check location validity - if (layer > layers >> 1) { - if (index2 - index1 != n >> (layers - layer)) - return false; - } - else{ - if (index2 - index1 != n >> (layer + 1)) - return false; - } - - // mark location in table - locationChecksum[layer][index1] = true; - locationChecksum[layer][index2] = true; - - // verify proof - if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1], - rerandomizableEncryptedMessages[layer][index2], - rerandomizableEncryptedMessages[layer + 1][index1], - rerandomizableEncryptedMessages[layer + 1][index2], - zkp)) { - - verifier.verify(rerandomizableEncryptedMessages[layer][index1], - rerandomizableEncryptedMessages[layer][index2], - rerandomizableEncryptedMessages[layer + 1][index1], - rerandomizableEncryptedMessages[layer + 1][index2], - zkp); - System.out.print("\n\n\nlayer " + layer + " i , j " + index1 + " , " + index2 + "\n\n\n"); - return false; - } - } - } - - // verify all necessary locations for BeneshNet were proved - for (boolean[] checksumLayer: locationChecksum) { - for (boolean locationBoolean: checksumLayer) { - if (!locationBoolean) - return false; - } - } - return true; - } -} diff --git a/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java deleted file mode 100644 index e0695bc..0000000 --- a/mixer/src/main/java/verifier/ZeroKnowledgeOrProofParser.java +++ /dev/null @@ -1,69 +0,0 @@ -package verifier; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Mixing; -import org.bouncycastle.math.ec.ECPoint; -import org.factcenter.qilin.primitives.concrete.ECGroup; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 1/25/2016. - */ -public class ZeroKnowledgeOrProofParser { - - private final ECGroup group; - public ZeroKnowledgeOrProofParser(ECGroup group) { - this.group = group; - } - - public ECPoint convert2ECPoint(ByteString bs){ - return group.decode(bs.toByteArray()); - } - - public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ - return new ZeroKnowledgeOrProofContainer(orProof); - } - - public class ZeroKnowledgeOrProofContainer{ - public final ECPoint g1,g2,h1,h2; - public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; - public final ECPoint u,v,uTag,vTag; - public final BigInteger c1,c2,z,zTag; - public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; - - private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ - this.forRandomOracle = - Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() - .setG1(orProof.getG1()) - .setH1(orProof.getH1()) - .setG2(orProof.getG2()) - .setH2(orProof.getH2()) - .setG1Tag(orProof.getG1Tag()) - .setH1Tag(orProof.getH1Tag()) - .setG2Tag(orProof.getG2Tag()) - .setH2Tag(orProof.getH2Tag()) - .setU(orProof.getU()) - .setV(orProof.getV()) - .setUTag(orProof.getUTag()) - .setVTag(orProof.getVTag()) - .build(); - this.g1 = convert2ECPoint(orProof.getG1()); - this.g2 = convert2ECPoint(orProof.getG2()); - this.h1 = convert2ECPoint(orProof.getH1()); - this.h2 = convert2ECPoint(orProof.getH2()); - this.g1Tag = convert2ECPoint(orProof.getG1Tag()); - this.g2Tag = convert2ECPoint(orProof.getG2Tag()); - this.h1Tag = convert2ECPoint(orProof.getH1Tag()); - this.h2Tag = convert2ECPoint(orProof.getH2Tag()); - this.u = convert2ECPoint(orProof.getU()); - this.v = convert2ECPoint(orProof.getV()); - this.uTag = convert2ECPoint(orProof.getUTag()); - this.vTag = convert2ECPoint(orProof.getVTag()); - this.c1 = new BigInteger(orProof.getC1().toByteArray()); - this.c2 = new BigInteger(orProof.getC2().toByteArray()); - this.z = new BigInteger(orProof.getZ().toByteArray()); - this.zTag = new BigInteger(orProof.getZTag().toByteArray()); - } - } -} diff --git a/mixer/src/test/java/mixer/CreateTestVector.java b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java similarity index 97% rename from mixer/src/test/java/mixer/CreateTestVector.java rename to mixer/src/test/java/meerkat/mixer/CreateTestVector.java index ed43995..69a1637 100644 --- a/mixer/src/test/java/mixer/CreateTestVector.java +++ b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java @@ -1,10 +1,13 @@ -package mixer; +package meerkat.mixer; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; +import mixer.Mixer; +import mixer.MixerOutput; +import mixer.Utils; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.ECElGamal; diff --git a/mixer/src/test/java/mixer/MixNetworkTest.java b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java similarity index 97% rename from mixer/src/test/java/mixer/MixNetworkTest.java rename to mixer/src/test/java/meerkat/mixer/MixNetworkTest.java index d5faed5..7755fd4 100644 --- a/mixer/src/test/java/mixer/MixNetworkTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; /** * Created by Tzlil on 12/17/2015. diff --git a/mixer/src/test/java/mixer/MixingTest.java b/mixer/src/test/java/meerkat/mixer/MixingTest.java similarity index 99% rename from mixer/src/test/java/mixer/MixingTest.java rename to mixer/src/test/java/meerkat/mixer/MixingTest.java index 63f6426..626060f 100644 --- a/mixer/src/test/java/mixer/MixingTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixingTest.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; /** * Created by Tzlil on 12/30/2015. diff --git a/mixer/src/test/java/mixer/RerandomizeTest.java b/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java similarity index 99% rename from mixer/src/test/java/mixer/RerandomizeTest.java rename to mixer/src/test/java/meerkat/mixer/RerandomizeTest.java index 034e311..7f1175c 100644 --- a/mixer/src/test/java/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; diff --git a/mixer/src/test/java/mixer/SimpleRerandomizeTest.java b/mixer/src/test/java/meerkat/mixer/SimpleRerandomizeTest.java similarity index 99% rename from mixer/src/test/java/mixer/SimpleRerandomizeTest.java rename to mixer/src/test/java/meerkat/mixer/SimpleRerandomizeTest.java index 34df02b..27e4d2d 100644 --- a/mixer/src/test/java/mixer/SimpleRerandomizeTest.java +++ b/mixer/src/test/java/meerkat/mixer/SimpleRerandomizeTest.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/mixer/Utils.java b/mixer/src/test/java/meerkat/mixer/Utils.java similarity index 99% rename from mixer/src/test/java/mixer/Utils.java rename to mixer/src/test/java/meerkat/mixer/Utils.java index 78e789e..38ed3cc 100644 --- a/mixer/src/test/java/mixer/Utils.java +++ b/mixer/src/test/java/meerkat/mixer/Utils.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; import com.google.protobuf.ByteString; import com.google.protobuf.GeneratedMessage; diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java similarity index 99% rename from mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java rename to mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java index 413fbc8..a87d043 100644 --- a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java @@ -1,4 +1,4 @@ -package mixer; +package meerkat.mixer; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; From e677355040ae42a7908bd46bbea68c8b1ca0b189 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 17 Apr 2016 09:09:13 +0300 Subject: [PATCH 25/66] comments: --- .../java/meerkat/crypto/mixnet/Mixer.java | 3 +- .../meerkat/mixer/main/BatchConverter.java | 118 +++++++ .../java/meerkat/mixer/main/BatchHandler.java | 101 +++++- .../java/meerkat/mixer/main/MainMixing.java | 105 +++++- .../java/meerkat/mixer/mixing/MixNetwork.java | 209 +++++++++++- .../main/java/meerkat/mixer/mixing/Mixer.java | 192 ++++++++++- .../meerkat/mixer/mixing/MixerOutput.java | 127 +++++++- .../mixer/mixing/RandomPermutation.java | 40 ++- .../java/meerkat/mixer/mixing/Switch.java | 33 +- .../necessary/AsyncBulletinBoardClient.java | 77 ++++- .../mixer/necessary/BulletinBoardClient.java | 58 +++- .../mixer/necessary/CompleteBatch.java | 65 +++- .../mixer/prover/ElGamalProofOrganizer.java | 298 +++++++++++++++++- .../java/meerkat/mixer/prover/Prover.java | 213 ++++++++++++- .../java/meerkat/mixer/verifier/Verifier.java | 92 +++++- .../meerkat/mixer/verifier/VerifyTable.java | 88 +++++- .../verifier/ZeroKnowledgeOrProofParser.java | 90 +++++- .../java/meerkat/mixer/CreateTestVector.java | 21 +- .../java/meerkat/mixer/MixNetworkTest.java | 3 + .../test/java/meerkat/mixer/MixingTest.java | 11 +- .../meerkat/mixer/ZeroKnowledgeProofTest.java | 4 +- .../java/profiling/BigInteger/AddSub.java | 2 +- .../BigInteger/GenerateRandomness.java | 2 +- .../java/profiling/BigInteger/Modulo.java | 2 +- .../test/java/profiling/BigInteger/Mul.java | 2 +- .../profiling/Convert/ByteString2ECPoint.java | 2 +- ...bleEncryptedMessage2ElGamalCiphertext.java | 2 +- .../src/test/java/profiling/ECGroup/Add.java | 2 +- .../test/java/profiling/ECGroup/Encode.java | 2 +- .../src/test/java/profiling/ECGroup/Mul.java | 2 +- .../test/java/profiling/ECGroup/Negate.java | 2 +- .../src/test/java/profiling/Rerandomize.java | 2 +- .../java/profiling/ZeroKnowledgeProof.java | 4 +- 33 files changed, 1917 insertions(+), 57 deletions(-) create mode 100644 mixer/src/main/java/meerkat/mixer/main/BatchConverter.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 4262012..a9b61d7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -4,11 +4,12 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto; import java.util.List; +import java.util.Random; /** * Created by talm on 25/10/15. */ public interface Mixer { - public MixerOutput mix(List ciphertexts) + public MixerOutput mix(List ciphertexts,Random random) throws InvalidProtocolBufferException; } diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java new file mode 100644 index 0000000..f2d02dd --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java @@ -0,0 +1,118 @@ +package meerkat.mixer.main; + +import com.google.protobuf.ByteString; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Tzlil on 12/17/2015. + * provide convert operation from batch data to meerkat.mixer.mixing output and backwards + */ +public class BatchConverter { + + private final int n,layers; + + /** + * constructor + * @param n + * @param layers + */ + public BatchConverter(int n,int layers){ + this.n = n; + this.layers = layers; + } + + /** + * convert integer to byte string + * @param a + * @return a as byte string + */ + private ByteString Integer2ByteString(int a){ + return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); + } + + /** + * convert byte string to integer + * @param bs + * @return bs as int + */ + private int ByteString2Integer(ByteString bs) { + return Integer.valueOf(bs.toString()); + } + + /** + * convert meerkat.mixer.mixing output to batch data + * @param mixerOutput + * @return meerkat.mixer.mixing output as list of batch data + */ + public List MixerOutput2BatchData(MixerOutput mixerOutput) { + + List result = new ArrayList(); + + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(Integer2ByteString(n)) + .build()); + + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) { + for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(zkp.toByteString()) + .build()); + } + } + for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.getEncryptedMessages()) { + for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(encryption.toByteString()) + .build()); + } + } + return result; + } + + /** + * convert batch data list to meerkat.mixer.mixing output + * @param batchDataList + * @return batch data list as MixerOutput + * @throws Exception + */ + public MixerOutput BatchDataList2MixerOutput + (List batchDataList) throws Exception { + + if (n != ByteString2Integer(batchDataList.remove(0).getData())){ + throw new Exception(); + } + + int nDiv2 = n >>1; + Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; + for (int layer = 0; layer < layers; layer++) + { + for (int proofIndex = 0 ; proofIndex < nDiv2 ; proofIndex ++) + { + proofs[layer][proofIndex] = Mixing.ZeroKnowledgeProof.parseFrom(batchDataList.remove(0).getData()); + } + } + + Crypto.RerandomizableEncryptedMessage[][] encryptions + = new Crypto.RerandomizableEncryptedMessage[layers + 1][n]; + for (int layer = 0; layer < layers + 1; layer++) + { + for (int encryptionIndex = 0 ; encryptionIndex < n ; encryptionIndex ++) + { + encryptions[layer][encryptionIndex] = Crypto.RerandomizableEncryptedMessage + .parseFrom(batchDataList.remove(0).getData()); + } + } + + return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions); + + } + +} + diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java index dee9129..e609234 100644 --- a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java +++ b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java @@ -1,7 +1,104 @@ package meerkat.mixer.main; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto; +import meerkat.mixer.necessary.AsyncBulletinBoardClient; +import meerkat.mixer.necessary.CompleteBatch; +import meerkat.mixer.verifier.VerifyTable; + +import java.util.Arrays; +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * implements AsyncBulletinBoardClient.ClientCallback */ -public class BatchHandler { +public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback { + + private MixerOutput mixerOutput; + private boolean msgReceived; + private Throwable t; + private CompleteBatch msg; + + private final int n, layers; + private final Mix2ZeroKnowledgeVerifier verifier; + + /** + * constructor + * @param n + * @param layers + * @param verifier + */ + public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) { + this.mixerOutput = null; + this.n = n; + this.layers = layers; + this.msgReceived = false; + this.t = null; + this.verifier = verifier; + } + + @Override + public void handleCallback(CompleteBatch msg) { + this.msg = msg; + synchronized (this) { + this.msgReceived = true; + notifyAll(); + } + } + + @Override + public void handleFailure(Throwable t) { + this.t = t; + synchronized (this) { + this.msgReceived = true; + notifyAll(); + } + } + + /** + * return true iff msg was received + * @return msgReceived + */ + public boolean isMsgReceived() { + return msgReceived; + } + + /** + * convert batch data to meerkat.mixer.mixing output + * @throws Exception + */ + private void convertMessage() throws Exception { + BatchConverter batchConverter = new BatchConverter(n,layers); + this.mixerOutput = batchConverter.BatchDataList2MixerOutput(msg.getBatchDataList()); + } + + /** + * call convert message, and if succeed verify the table + * @return return true iff the given batch message is valid meerkat.mixer.mixing output + * @throws Exception + */ + public boolean verifyTable() throws Exception { + if (mixerOutput == null) { + convertMessage(); + } + return VerifyTable.verifyTable(verifier, n, mixerOutput); + } + + /** + * extract input for meerkat.mixer.mixing from previous mixers output + * @return last layer of encrypted votes as list + * @throws Throwable in case if failure + */ + public List getInputForMixer() throws Throwable { + if (t != null) { + throw t; + } + if(!verifyTable()){ + throw new Exception("in valid table"); + } + return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1 + } } + diff --git a/mixer/src/main/java/meerkat/mixer/main/MainMixing.java b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java index 27b6fca..62978e8 100644 --- a/mixer/src/main/java/meerkat/mixer/main/MainMixing.java +++ b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java @@ -1,7 +1,110 @@ package meerkat.mixer.main; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.Mixer; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.Crypto; +import meerkat.mixer.mixing.MixNetwork; +import meerkat.mixer.necessary.AsyncBulletinBoardClient; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * this class define all the operation meerkat.mixer.mixing party should do: + * 1. receive previous mixers output (re encrypted votes + proofs) + * 2. verify its input + * 3. mix + * 4. send the meerkat.mixer.mixing output */ public class MainMixing { + + private final Mixer mixer; + private final Mix2ZeroKnowledgeVerifier verifier; + private final int n, layers; + private final AsyncBulletinBoardClient asyncBulletinBoardClient; + private final byte[] id; + + + /** + * constructor + * @param mixer + * @param verifier + * @param n + * @param asyncBulletinBoardClient + * @param id + */ + public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n + , AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) { + this.mixer = mixer; + this.verifier = verifier; + this.n = n; + this.layers = MixNetwork.numberOfLayers(n); + this.asyncBulletinBoardClient = asyncBulletinBoardClient; + this.id = id; + } + + /** + * + * @param prevBatchIds + * @param batchId + * @param random + * @param callback + * @throws Throwable + */ + public void main(List prevBatchIds, int batchId, Random random, AsyncBulletinBoardClient.ClientCallback callback) throws Throwable { + + List mixerInput; + + List batchHandlers = new ArrayList(prevBatchIds.size()); + BatchHandler currentBatchHandler; + for (Integer prevBatchId : prevBatchIds) { + currentBatchHandler = new BatchHandler(n, layers,verifier); + asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); + batchHandlers.add(currentBatchHandler); + } + // check all handlers messages were received + for (BatchHandler batchHandler : batchHandlers) { + synchronized (batchHandler){ + if(!batchHandler.isMsgReceived()) + batchHandler.wait(); + } + } + // assert all handlers succeeded + for (BatchHandler batchHandler : batchHandlers) { + if(!batchHandler.verifyTable()){ + throw new Exception("invalid input"); + } + } + + BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); + mixerInput = lastBatchHandler.getInputForMixer(); + + MixerOutput mixerOutput = mixer.mix(mixerInput,random); + updateBB(mixerOutput, batchId, callback); + + } + + /** + * send meerkat.mixer.mixing output to BB + * @param mixerOutput + * @param batchId + * @param callback + */ + private void updateBB(MixerOutput mixerOutput + , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { + + BatchConverter batchConverter = new BatchConverter(n,layers); + List batchDataList = batchConverter.MixerOutput2BatchData(mixerOutput); + asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); + } + + + + } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java index 71770ce..e820ebd 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java @@ -1,7 +1,214 @@ package meerkat.mixer.mixing; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/15/2015. + * contains benes mix network. + * the network is generated in the constructor and can't be change */ public class MixNetwork { + + private final Switch[][] switches; + + /** + * constructor + * @param randomPermutation + */ + public MixNetwork(RandomPermutation randomPermutation) { + this.switches = generateSwitchesValue(randomPermutation.permutation); + } + + /** + * implements benes mix network algorithm + * @param permutation - random permutation + * @return switches + */ + private Switch[][] generateSwitchesValue(int[] permutation){ + int n = permutation.length; + assert ((n & n-1) == 0); //n == 2^k + int layers = numberOfLayers(n); + + int[] pi, piL, piR; + Queue permutationsQueue = new ArrayBlockingQueue(n); + Graph graph; + int iDiv2; + int nDiv2 = n >> 1; + Switch[][] switches = new Switch[layers][nDiv2]; + int index1,index2; + + permutationsQueue.add(permutation); + for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size + { + iDiv2 = i >> 1; + for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation start index + { + pi = permutationsQueue.remove(); + graph = new Graph(pi); + piL = new int[iDiv2]; + piR = new int[iDiv2]; + for (int k = 0; k < iDiv2; k++){ // k == switch index in permutation j + + index1 = k + (j << 1); + index2 = index1 + iDiv2; + switches[layers - layer - 1][k + j] = new Switch(index1,index2,layers - layer - 1,graph.getSwitchValue(k, true)); + switches[layer][k + j] = new Switch(index1,index2,layer,graph.getSwitchValue(k, false)); + + if (!switches[layers - layer - 1][k + j].value) { + piL[k] = pi[k] % iDiv2; + piR[k] = pi[k + iDiv2] % iDiv2; + } else { + piL[k] = pi[k + iDiv2] % iDiv2; + piR[k] = pi[k] % iDiv2; + } + } + permutationsQueue.add(piL); + permutationsQueue.add(piR); + } + } + return switches; + } + + /** + * getter for switches value at layer + * @param layer + * @return switches[layer] + */ + public Switch[] getSwitchesByLayer(int layer) + { + return switches[layer]; + } + + /** + * calc number of layers for n values + * @param n number of votes + * @return layers + */ + public static int numberOfLayers(int n){ + return (int) (2 * Math.log(n) / Math.log(2)) - 1; + } + + /** + * inner class + * graph object, part of benes mix network algorithm + */ + private class Graph { + private int n; + private int nDiv2; + private Node[][] nodes; + protected Graph(int[] permutation){ + n = permutation.length; // n = 2^k + nDiv2 = n >> 1; + createNodes(); + createEdges(permutation); + setSwitches(); + } + + /** + * provide an access to algorithm result + * index must be less then n/2 + */ + protected boolean getSwitchValue(int index,boolean up) { + return up ? nodes[0][index].value : nodes[1][index].value; + } + + + + + + + /** + * create two lines of nodes size n/2 each + * the value of the i th node is (i,i+n/2) if i < n /2 (first line) + * otherwise its value is (i - n/2 , i) (second line) + */ + private void createNodes() { + nodes = new Node[2][nDiv2]; + for (int i = 0; i < nDiv2; i++) { + nodes[0][i] = new Node(); + nodes[1][i] = new Node(); + } + } + + /** create an edge between each pair of nodes i,j from different lines (i index of the first line) + * if exists k in i th node's value and t in j th node's value + * s.t permutation[k] == t + * the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) + * Note: in purpose to avoid edge cases, each node has exactly two edges + */ + private void createEdges(int[] permutation) { + int j; + for (int i = 0; i < nDiv2; i++) { + j = permutation[i] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i] >= nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i] >= nDiv2))); + + j = permutation[i + nDiv2] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i + nDiv2] < nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i + nDiv2] < nDiv2))); + } + } + + /** + * set switch's value (on/off) for each switch (node) + * s.t if nodes i,j connected by edge e, i th switch's value + * must be equal to j's if e is broken or not equal if e is not broken + */ + private void setSwitches() { + Node node; + boolean v; + Edge e0,e1; + // iterate over first line of nodes + for (int i = 0; i < nDiv2; i++) { + node = nodes[0][i]; + if (node.set) + continue; + //select default value for first node in connected component + v = false; + // set value to all reachable nodes from node + while (true) { + node.set = true; + node.value = v; + e0 = node.edges.get(0); e1 = node.edges.get(1); + if (e0.neighbor.set && e1.neighbor.set) + break; + v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; + node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; + } + } + } + + /** + * inner class + * node object in graph + * there are exactly twp edges for each node + */ + private class Node { + public List edges; + private boolean value; + private boolean set; + public Node() { + edges = new ArrayList(2); + set = false; + } + } + + /** + * inner class + * edge object in graph + */ + private class Edge { + public Node neighbor; + public boolean broken; + public Edge(Node neighbor, boolean broken) { + this.neighbor = neighbor; + this.broken = broken; + } + } + } + + } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java index c405784..fbe091c 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java @@ -1,7 +1,193 @@ package meerkat.mixer.mixing; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.Encryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto.EncryptionRandomness; +import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage; +import meerkat.protobuf.Mixing.ZeroKnowledgeProof; + +import java.util.List; +import java.util.Random; + /** - * Created by Tzlil on 4/16/2016. + * an implementation of meerkat.crypto.mixnet.Mixer + * meerkat.mixer.mixing algorithm on set of n encrypted votes: + * 0. asset n is power of two + * 1. set switches according to benes network on random permutation + * 2. re encrypt and mix with respect to switches values (encryptor.rerandomize) + * 3. generate zero knowledge proof on each re encrypted couple + * 4. return proofs table + encryption table + * */ -public class Mixer { -} +public class Mixer implements meerkat.crypto.mixnet.Mixer { + + private final Mix2ZeroKnowledgeProver prover; + private final Encryption encryptor; + + /** + * constructor + * @param prover + * @param encryptor + */ + public Mixer(Mix2ZeroKnowledgeProver prover, Encryption encryptor) { + this.prover = prover; + this.encryptor = encryptor; + } + + /** + * return True iff n == 2 ^ k + * @param n + * @return + */ + public static boolean isPowerOfTwo(int n){ + return (n & (n - 1)) == 0; + } + + /** + * initialize encryption table of size (layers + 1)* n + * @param n number of votes + * @param layers + * @param ciphertexts encrypted votes + * @return an initialized encryption table s.t first layer == given encrypted votes + */ + private RerandomizableEncryptedMessage[][] initializeEncryptionTable(int n,int layers,List ciphertexts){ + // set first level of encryption + RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; + for (int j = 0; j < n; j++) { + encryptionTable[0][j] = ciphertexts.get(j); + } + return encryptionTable; + } + + /** + * generate randomness for all rerandomize operations + * @param n number of votes + * @param layers + * @return an initialized randomness table of size layers * n + */ + private EncryptionRandomness[][] generateRandomnessesForRerandomize(int n,int layers,Random random){ + EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; + for (int layer = 0; layer < layers; layer++) + { + for (int i = 0; i < n; i++) { + randomnesses[layer][i] = encryptor.generateRandomness(random);; + } + } + return randomnesses; + } + + /** + * generate new random mix network + * @param n number of votes + * @param random + * @return new random mix network + */ + private MixNetwork generateMixNetwork(int n,Random random){ + return new MixNetwork(new RandomPermutation(n,random)); + } + + /** + * fills the encryption table with rerandomize encrypted votes. + * @param layers + * @param mixNetwork switches table (boolean values) + * @param encryptionTable an initialized encryption table s.t first layer == given encrypted votes + * @param randomnesses an initialized randomness table of size layers * n, use for rerandomize operations + * @throws InvalidProtocolBufferException + */ + private void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable + ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + Switch[] switchesLayer; + int index1,index2; + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; + if (!sw.value) { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); + + } else { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); + } + } + } + } + + /** + * generate zero knowledge proof for each rerandomize encrypted votes couple in encryptionTable + * @param n number of votes + * @param layers + * @param mixNetwork switches table (boolean values) used for set encryption table + * @param encryptionTable full encryption table + * @param randomnesses randomness table of size layers * n, used for set encryption table + * @return zero knowledge proofs table + * @throws InvalidProtocolBufferException + */ + private ZeroKnowledgeProof[][] generateZeroKnowledgeProofTable(int n, int layers, MixNetwork mixNetwork + , RerandomizableEncryptedMessage[][] encryptionTable + , EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + Switch[] switchesLayer; + int index1,index2; + int switchIndex = 0; + int nDiv2 = n >> 1; + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; + + proofsTable[layer][switchIndex] = + prover.prove(e1, e2, encryptionTable[layer + 1][index1], + encryptionTable[layer + 1][index2], + sw.value, sw.i, sw.j, sw.layer, r1, r2); + + switchIndex = (switchIndex + 1) % nDiv2; + } + } + return proofsTable; + } + + /** + * mix given encrypted votes using random + * @param ciphertexts encrypted votes + * @param random + * @return meerkat.mixer.mixing result + * @throws InvalidProtocolBufferException + */ + public MixerOutput mix(List ciphertexts,Random random) throws InvalidProtocolBufferException { + + int n = ciphertexts.size(); + assert (n > 1 && isPowerOfTwo(n)); + + int layers = MixNetwork.numberOfLayers(n); // layers = 2logn -1 + RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts); + EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random); + MixNetwork mixNetwork = generateMixNetwork(n,random); + rerandomize(layers,mixNetwork,encryptionTable,randomnesses); + ZeroKnowledgeProof[][] proofsTable = generateZeroKnowledgeProofTable(n,layers,mixNetwork,encryptionTable,randomnesses); + + return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable); + } + +} \ No newline at end of file diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java index dbeac75..64636cc 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java @@ -1,7 +1,130 @@ package meerkat.mixer.mixing; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 1/18/2016. + * implements meerkat.crypto.mixnet.MixerOutput interface + * container for meerkat.mixer.mixing.mix result. */ -public class MixerOutput { +public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ + private final Mixing.ZeroKnowledgeProof[][] proofs; + private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; + private final int n; + private final int layers; + + /** + * constructor + * @param n number of votes + * @param layers + * @param encryptedMessages at level 0 , contains the original encrypted votes + * at each other level contains the re encrypted votes + * @param proofs in each cell (level,switch) contains the match zero knowledge proof + */ + public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs + , Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { + this.proofs = proofs; + this.encryptedMessages = encryptedMessages; + this.n = n; + this.layers = layers; + } + + + + @Override + public Mixing.ZeroKnowledgeProof[][] getProofs() { + return proofs; + } + + @Override + public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() { + return encryptedMessages; + } + + @Override + public int getN() { + return n; + } + + /** + * print the output, encrypted messages and proofs, to folder + * @param dir - directory + * @throws IOException + */ + public void outToFolder(String dir) throws IOException { + + (new File(dir)).mkdirs(); + //create files + String proofsDir = dir + "/Proofs"; + String encDir = dir + "/EncryptedMessages"; + (new File(proofsDir)).mkdir(); + (new File(encDir)).mkdir(); + for (int layer = 0; layer < layers; layer++){ + (new File(proofsDir +"/layer" + layer )).mkdir(); + (new File(encDir +"/layer" + layer )).mkdir(); + } + (new File(encDir +"/input")).mkdir(); + + + for (int layer = 0; layer < layers; layer++){ + for(int i = 0; i < proofs[layer].length; i ++){ + writeProofToFile(proofsDir,proofs[layer][i]); + } + } + + for (int layer = 0; layer <= layers; layer++){ + for(int i = 0; i < encryptedMessages[layer].length; i ++){ + writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]); + } + } + } + + /** + * create new file contains single proof + * @param proofsDir + * @param proof + * @throws IOException + */ + private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException { + Mixing.ZeroKnowledgeProof.Location location = proof.getLocation(); + int layer = location.getLayer(); + int i = location.getI(); + int j = location.getJ(); + String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(proof.toByteArray()); + fos.close(); + } + + /** + * create new file contains single encrypted message + * @param encDir + * @param layer + * @param i + * @param enc + * @throws IOException + */ + private void writeEncToFile(String encDir,int layer,int i, Crypto.RerandomizableEncryptedMessage enc) throws IOException { + + String fileName; + if(layer >= 0) + fileName = encDir+"/layer" + layer +"/" + i; + else + fileName = encDir+"/input/" + i; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(enc.toByteArray()); + fos.close(); + } } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java index 9202403..7f18530 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java @@ -1,7 +1,45 @@ package meerkat.mixer.mixing; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * container for random permutation + * the permutation is sated in constructor and can't be change */ public class RandomPermutation { + public final int[] permutation; + + /** + * constructor + * @param n permutation size + * @param random + */ + public RandomPermutation(int n,Random random) { + this.permutation = generatePermutation(n,random); + } + + /** + * generate random permutation ovver [0,n) + * @param n permutation size + * @param random + * @return permutation + */ + private int[] generatePermutation(int n,Random random){ + List numbers= new ArrayList(n); + for (int i = 0; i < n; i++) { + numbers.add(i); + } + + int[] result = new int[n]; + int index; + for (int i = 0; i < n; i++) { + index = random.nextInt(n - i); + result[i] = numbers.get(index); + numbers.remove(index); + } + return result; + } } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Switch.java b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java index 0d9c17e..5de522e 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Switch.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java @@ -1,7 +1,36 @@ package meerkat.mixer.mixing; /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/15/2015. + * container for switch */ -public class Switch { +public class Switch{ + + public final int i, j, layer; + public final boolean value; + + /** + * constructor + * @param i + * @param j + * @param layer + * @param value the switch is on or off + */ + public Switch(int i, int j, int layer, boolean value) { + this.i = i; + this.j = j; + this.layer = layer; + this.value = value; + } + + + @Override + public String toString() { + return "Switch{" + + "i=" + i + + ", j=" + j + + ", layer=" + layer + + ", value=" + value + + '}'; + } } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java index 410bf54..d1a2d9f 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java @@ -1,7 +1,80 @@ package meerkat.mixer.necessary; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * ToDo: this should be replaced by AsyncBulletinBoardClient at BB project */ -public class AsyncBulletinBoardClient { +public interface AsyncBulletinBoardClient extends BulletinBoardClient { + + public interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + public interface MessageHandler { + void handleNewMessages(List messageList); + } + + /** + * Post a message to the bulletin board in an asynchronous manner + * @param msg is the message to be posted + * @param callback is a class containing methods to handle the result of the operation + * @return a unique message ID for the message, that can be later used to retrieve the batch + */ + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + + /** + * This method allows for sending large messages as a batch to the bulletin board + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param batchDataList is the (canonically ordered) list of data comprising the batch message + * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) + * @param callback is a callback function class for handling results of the operation + * @return a unique message ID for the entire message, that can be later used to retrieve the batch + */ + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatch method in which startPosition is set to the default value 0 + */ + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + + /** + * Check how "safe" a given message is in an asynchronous manner + * The result of the computation is a rank between 0.0 and 1.0 indicating the fraction of servers containing the message + * @param id is the unique message identifier for retrieval + * @param callback is a callback function class for handling results of the operation + */ + public void getRedundancy(MessageID id, ClientCallback callback); + + /** + * Read all messages posted matching the given filter in an asynchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @param callback is a callback function class for handling results of the operation + */ + public void readMessages(MessageFilterList filterList, ClientCallback> callback); + + /** + * Read a given batch message from the bulletin board + * @param signerId is the ID of the signer (sender) of the batch message + * @param batchId is the unique (per signer) ID of the batch + * @param callback is a callback class for handling the result of the operation + */ + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * @param filterList defines the set of filters for message retrieval + * @param messageHandler defines the handler for new messages received + */ + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); + } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java index a4e0a0a..aebe469 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java @@ -1,7 +1,61 @@ package meerkat.mixer.necessary; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.Voting.BulletinBoardClientParams; + +import java.util.List; + +import static meerkat.protobuf.BulletinBoardAPI.*; + /** - * Created by Tzlil on 4/16/2016. + * Created by talm on 24/10/15. + * + * ToDo: this should be replaced by BulletinBoardClient at BB project */ -public class BulletinBoardClient { +public interface BulletinBoardClient { + + interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + /** + * Initialize the client to use some specified servers + * @param clientParams contains the parameters required for the client setup + */ + void init(BulletinBoardClientParams clientParams); + + /** + * Post a message to the bulletin board in a synchronous manner + * @param msg is the message to be posted + * @return a unique message ID for the message, that can be later used to retrieve the batch + * @throws CommunicationException + */ + MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; + + + + /** + * Check how "safe" a given message is in a synchronous manner + * @param id is the unique message identifier for retrieval + * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) + */ + float getRedundancy(MessageID id); + + /** + * Read all messages posted matching the given filter in a synchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @return the list of messages + */ + List readMessages(MessageFilterList filterList); + + /** + * Closes all connections, if any. + * This is msgRecived in a synchronous (blocking) way. + */ + void close(); + } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java index b8067e5..c93506e 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java @@ -1,7 +1,70 @@ package meerkat.mixer.necessary; + +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.*; + +import java.util.LinkedList; +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * A data structure for holding a complete batch message along with its signature + * + * ToDo: this should be replaced by CompleteBatch at BB project */ public class CompleteBatch { + + private BeginBatchMessage beginBatchMessage; + private List batchDataList; + private Signature signature; + + public CompleteBatch() { + batchDataList = new LinkedList(); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { + this(); + beginBatchMessage = newBeginBatchMessage; + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList) { + this(newBeginBatchMessage); + appendBatchData(newDataList); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature) { + this(newBeginBatchMessage, newDataList); + signature = newSignature; + } + + public BeginBatchMessage getBeginBatchMessage() { + return beginBatchMessage; + } + + public List getBatchDataList() { + return batchDataList; + } + + public Signature getSignature() { + return signature; + } + + public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { + this.beginBatchMessage = beginBatchMessage; + } + + public void appendBatchData(BatchData newBatchData) { + batchDataList.add(newBatchData); + } + + public void appendBatchData(List newBatchDataList) { + batchDataList.addAll(newBatchDataList); + } + + public void setSignature(Signature newSignature) { + signature = newSignature; + } + } diff --git a/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java index 1d2272b..153dc12 100644 --- a/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java +++ b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java @@ -1,7 +1,303 @@ package meerkat.mixer.prover; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; + /** - * Created by Tzlil on 4/16/2016. + * use for organize the input for each ZKP + * + * both meerkat.mixer.prover and meerkat.mixer.verifier implantation are using it */ public class ElGamalProofOrganizer { + + private final ECGroup group; + private final ECPoint g; + private final ECPoint h; + private final byte[] gEncoded; + private final byte[] hEncoded; + + /** + * @param group + * @param g - generator of group + * @param h - h = g ^ SecretKey + */ + public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){ + this.group = group; + this.g = g; + this.h = h; + this.gEncoded = group.encode(g); + this.hEncoded = group.encode(h); + } + + public enum OrProofOrder { + first, second, third, fourth + } + + public enum TrueCouple { + left, right, unknown + } + + /** + * can be used by meerkat.mixer.prover only + * + * call to the meerkat.mixer.main overload with flag = true + */ + protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException { + + //boolean flag = true; + return createProofInput(in1,in2,out1,out2,r1,r2,switched,true); + } + + /** + * can be used by anyone, e.g meerkat.mixer.verifier + * + * call to the meerkat.mixer.main overload with flag = false + */ + public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException { + + // flag = false; + return createProofInput(in1,in2,out1,out2,null,null,false,false); + } + + /** + * inner method + * convert each encrypted message to ElGamalCiphertext + * + * @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known) + * @return ElGamalProofInput + * @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't + * ElGamalCiphertext + */ + private ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag) + throws InvalidProtocolBufferException { + + //convert RerandomizableEncryptedMessage to ElGamalCiphertext + ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1); + ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2); + ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1); + ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2); + + if(flag) { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched); + }else { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal); + } + } + + + /** + * can be construct by instance of organizer only by calling createProofInput method (all constructors are private) + * + * in construction it use for preparing the input for prove, while avoiding double converting or calculations + * + * use as a container for 4 OrProofInput. + */ + public class ElGamalProofInput { + + private final OrProofInput first; + private final OrProofInput second; + private final OrProofInput third; + private final OrProofInput fourth; + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + + /** + * @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known) + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag){ + + ECPoint e1c1 = convert2ECPoint(e1.getC1()); + ECPoint e1c2 = convert2ECPoint(e1.getC2()); + ECPoint e2c1 = convert2ECPoint(e2.getC1()); + ECPoint e2c2 = convert2ECPoint(e2.getC2()); + ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); + ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); + ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); + ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); + + ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); + ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); + ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); + ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); + + ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); + ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); + ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); + ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); + + + if(!flag){ + + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); + + }else { + + byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); + byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); + byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); + byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); + byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); + byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); + byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); + byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); + + + if (!switched) { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r1, TrueCouple.left); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.left); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + } else { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r2, TrueCouple.right); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.right); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.left); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r1, TrueCouple.left); + } + } + } + + + /** + * used by the meerkat.mixer.prover + * call to the meerkat.mixer.main constructor with flag = true + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){ + //flag = true; + this(e1,e2,e1New,e2New,r1,r2,switched,true); + } + + /** + * used by meerkat.mixer.prover + * call to the meerkat.mixer.main constructor with flag = true + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ + //flag = false; + this(e1,e2,e1New,e2New,null,null,false,false); + } + + /** + * getter for all 4 OrProofInputs + * + * @param orProofOrder + * @return the required OrProof + */ + public OrProofInput getOrProofInput(OrProofOrder orProofOrder) { + switch (orProofOrder) { + + case first: + return this.first; + case second: + return this.second; + case third: + return this.third; + case fourth: + return this.fourth; + } + return null; + } + } + + + /** + * can't be constructed (all constructors are private) + * + * 4 instances will be constructed for each new ElGamalProofInput + * + * container for all meerkat.mixer.necessary inputs for single OrProof + */ + public class OrProofInput{ + public final ECPoint g1; + public final ECPoint h1; + public final ECPoint g2; + public final ECPoint h2; + public final ECPoint g1Tag; + public final ECPoint h1Tag; + public final ECPoint g2Tag; + public final ECPoint h2Tag; + + // can be access by meerkat.mixer.prover only + protected final byte[] g1Encoded; + protected final byte[] h1Encoded; + protected final byte[] g2Encoded; + protected final byte[] h2Encoded; + protected final byte[] g1TagEncoded; + protected final byte[] h1TagEncoded; + protected final byte[] g2TagEncoded; + protected final byte[] h2TagEncoded; + protected final Crypto.EncryptionRandomness x; + protected final TrueCouple flag; + + /** + * used by meerkat.mixer.prover only + */ + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag + ,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded + , Crypto.EncryptionRandomness x, TrueCouple flag) { + this.g1 = g; + this.h1 = h1; + this.g2 = h; + this.h2 = h2; + this.g1Tag = g; + this.h1Tag = h1Tag; + this.g2Tag = h; + this.h2Tag = h2Tag; + + this.g1Encoded = gEncoded; + this.h1Encoded = h1Encoded; + this.g2Encoded = hEncoded; + this.h2Encoded = h2Encoded; + this.g1TagEncoded = gEncoded; + this.h1TagEncoded = h1TagEncoded; + this.g2TagEncoded = hEncoded; + this.h2TagEncoded = h2TagEncoded; + + this.x = x; + this.flag = flag; + + } + + /** + * used by meerkat.mixer.verifier + */ + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) { + this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown); + } + } } diff --git a/mixer/src/main/java/meerkat/mixer/prover/Prover.java b/mixer/src/main/java/meerkat/mixer/prover/Prover.java index 9bda892..303c560 100644 --- a/mixer/src/main/java/meerkat/mixer/prover/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/prover/Prover.java @@ -1,7 +1,216 @@ package meerkat.mixer.prover; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + + /** - * Created by Tzlil on 4/16/2016. + * implements of Mix2ZeroKnowledgeProver interface + * this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext */ -public class Prover { +public class Prover implements Mix2ZeroKnowledgeProver { + + private final ECGroup group; + private final RandomOracle randomOracle; + private final Random rand; + private final ECElGamalEncryption encryptor; + private final ECPoint g,h; + private final BigInteger groupOrderUpperBound; + private final ElGamalProofOrganizer organizer; + + /** + * @param rand + * @param encryptor + * @param randomOracle - use for Fiat–Shamir heuristic + */ + public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { + + this.rand = rand; + this.encryptor = encryptor; + this.randomOracle = randomOracle; + this.group = this.encryptor.getGroup(); + this.g = group.getGenerator(); + this.h = this.encryptor.getElGamalPK().getPK(); + this.organizer = new ElGamalProofOrganizer(group,g,h); + this.groupOrderUpperBound = group.orderUpperBound(); + } + + /** + * @param in1 + * @param in2 + * @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1) + * @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2) + * @param sw - flag + * @param i - column of in1 and out1 in encryption table + * @param j - column of in2 and out2 in encryption table + * @param layer - row of in1,in2 in encryption table + * @param r1 + * @param r2 + * @return - a valid ZKP that indeed out1,out2 calculated as required + * @throws InvalidProtocolBufferException + */ + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean sw,int i,int j, int layer, + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { + Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; + + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw); + + first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first)); + second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second)); + third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third)); + fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth)); + + Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() + .setI(i) + .setJ(j) + .setLayer(layer) + .build(); + + Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() + .setFirst(first) + .setSecond(second) + .setThird(third) + .setFourth(fourth) + .setLocation(location) + .build(); + return result; + } + + + /** + * Fiat–Shamir heuristic + * @param input - protobuf contains all parameters from the first step of the current prove + * @param randomOracle + * @return randomOracle.hash(input) + */ + public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input, RandomOracle randomOracle) { + byte[] arr = input.toByteArray(); + return new BigInteger(1,randomOracle.hash(arr,arr.length)); + } + + + /** + * @param orProofInput + * @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2) + * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.prover + */ + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) { + + ECPoint g1 = orProofInput.g1; + ECPoint h1 = orProofInput.h1; + ECPoint g2 = orProofInput.g2; + ECPoint h2 = orProofInput.h2; + + ECPoint g1Tag = orProofInput.g1Tag; + ECPoint h1Tag = orProofInput.h1Tag; + ECPoint g2Tag = orProofInput.g2Tag; + ECPoint h2Tag = orProofInput.h2Tag; + + BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + BigInteger c1,c2,z,zTag; + ECPoint u,v,uTag,vTag; + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + + switch (orProofInput.flag) { + case left: + c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + //step 1 + u = group.multiply(g1, r); + v = group.multiply(g2, r); + uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); + vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); + //step 2 + // c1 = (hash(input + step1) + group size - c2)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c1 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); + //step 3 + //z = (r + c1 * x) % group size; + z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); + break; + case right: + c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + //step 1 + uTag = group.multiply(g1Tag, r); + vTag = group.multiply(g2Tag, r); + u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); + v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); + //step 2 + // c1 = (hash(input + step1) + group size - c1)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c2 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); + //step 3 + //zTag = (r + c2 * x) % group size; + zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); + break; + default: + return null; + } + + + return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() + .setG1(forRandomOracle.getG1()) + .setH1(forRandomOracle.getH1()) + .setG2(forRandomOracle.getG2()) + .setH2(forRandomOracle.getH2()) + .setG1Tag(forRandomOracle.getG1()) + .setH1Tag(forRandomOracle.getH1Tag()) + .setG2Tag(forRandomOracle.getG2Tag()) + .setH2Tag(forRandomOracle.getH2Tag()) + .setU(forRandomOracle.getU()) + .setV(forRandomOracle.getV()) + .setUTag(forRandomOracle.getUTag()) + .setVTag(forRandomOracle.getVTag()) + .setC1(ByteString.copyFrom(c1.toByteArray())) + .setC2(ByteString.copyFrom(c2.toByteArray())) + .setZ(ByteString.copyFrom(z.toByteArray())) + .setZTag(ByteString.copyFrom(zTag.toByteArray())) + .build(); + } } + diff --git a/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java index 0b19faa..ed08512 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java @@ -1,7 +1,95 @@ package meerkat.mixer.verifier; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import meerkat.mixer.prover.ElGamalProofOrganizer; +import meerkat.mixer.prover.Prover; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; + /** - * Created by Tzlil on 4/16/2016. + * implements Mix2ZeroKnowledgeVerifier */ -public class Verifier { +public class Verifier implements Mix2ZeroKnowledgeVerifier { + + + private final ECGroup group; + private final RandomOracle randomOracle; + private final ECPoint g,h; + private final ElGamalProofOrganizer organizer; + private final ZeroKnowledgeOrProofParser parser; + + /** + * constructor + * @param encryptor should be as the encryptor used by meerkat.mixer.prover + * @param randomOracle should be as the random oracle used by meerkat.mixer.prover + */ + public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { + this.group = encryptor.getGroup(); + this.g = group.getGenerator(); + this.h = encryptor.getElGamalPK().getPK(); + this.randomOracle = randomOracle; + this.organizer = new ElGamalProofOrganizer(group,g,h); + this.parser = new ZeroKnowledgeOrProofParser(group); + } + + /** + * verify zero knowledge proof + * @param in1 + * @param in2 + * @param out1 + * @param out2 + * @param proof out1 = rerandomize(in1) && out2 = rerandomize(in2) + * || + * out1 = rerandomize(in2) && out2 = rerandomize(in1) + * @return true iff all 4 or proofs are valid + * @throws InvalidProtocolBufferException + */ + public boolean verify(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2); + return verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first), proof.getFirst())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second), proof.getSecond())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third), proof.getThird())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth), proof.getFourth()); + + } + + + /** + * + * @param orProofInput + * @param orProof + * @return verify single or proof + */ + private boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, + Mixing.ZeroKnowledgeProof.OrProof orProof) { + ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof); + return container.g1.equals(orProofInput.g1) && + container.h1.equals(orProofInput.h1) && + container.g2.equals(orProofInput.g2) && + container.h2.equals(orProofInput.h2) && + container.g1Tag.equals(orProofInput.g1Tag) && + container.h1Tag.equals(orProofInput.h1Tag) && + container.g2Tag.equals(orProofInput.g2Tag) && + container.h2Tag.equals(orProofInput.h2Tag) && + container.c1.add(container.c2).mod(group.orderUpperBound()) + .equals(Prover.hash(container.forRandomOracle,randomOracle).mod(group.orderUpperBound())) && + group.multiply(container.g1, container.z) + .equals(group.add(container.u, group.multiply(container.h1,container.c1))) && + group.multiply(container.g2, container.z) + .equals(group.add(container.v, group.multiply(container.h2,container.c1))) && + group.multiply(container.g1Tag, container.zTag) + .equals(group.add(container.uTag, group.multiply(container.h1Tag,container.c2))) && + group.multiply(container.g2Tag, container.zTag) + .equals(group.add(container.vTag, group.multiply(container.h2Tag,container.c2))); + + } } diff --git a/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java index 1158e2e..2bb3781 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java @@ -1,7 +1,91 @@ package meerkat.mixer.verifier; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.util.Arrays; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/30/2015. + * provide one operation - verify meerkat.mixer.mixing output */ -public class VerifyTable { +public final class VerifyTable { + /** + * constructor + * @param verifier + * @param n + * @param mixerOutput + * @return true iff the meerkat.mixer.mixing output is valid + * @throws InvalidProtocolBufferException + */ + public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput) + throws InvalidProtocolBufferException { + int index1,index2,layer; + + //assert n = 2^k + if ( (n &(n-1)) != 0) + throw new IllegalArgumentException("n"); + + int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1; + //initialize locationChecksum table + // use for check BeneshNet validity + boolean[][] locationChecksum = new boolean[layers][n]; + for (boolean[] locationChecksumLayer: locationChecksum) { + Arrays.fill(locationChecksumLayer,false); + } + + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs(); + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); + + for (int i = 0; i < zeroKnowledgeProofs.length ; i++){ + for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){ + Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j]; + Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + index1 = location.getI(); + index2 = location.getJ(); + layer = location.getLayer(); + + // check location validity + if (layer > layers >> 1) { + if (index2 - index1 != n >> (layers - layer)) + return false; + } + else{ + if (index2 - index1 != n >> (layer + 1)) + return false; + } + + // mark location in table + locationChecksum[layer][index1] = true; + locationChecksum[layer][index2] = true; + + // verify proof + if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp)) { + + verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp); + return false; + } + } + } + + // verify all meerkat.mixer.necessary locations for BeneshNet were proved + for (boolean[] checksumLayer: locationChecksum) { + for (boolean locationBoolean: checksumLayer) { + if (!locationBoolean) + return false; + } + } + return true; + } } diff --git a/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java index 44fe45d..01ff344 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java @@ -1,7 +1,95 @@ package meerkat.mixer.verifier; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 1/25/2016. + * zero knowledge proof parser */ public class ZeroKnowledgeOrProofParser { + + private final ECGroup group; + + /** + * parse or proof message and return the result in zero knowledge or proof container + * @param orProof + * @return zero knowledge or proof container + */ + public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ + return new ZeroKnowledgeOrProofContainer(orProof); + } + + /** + * getter + * @param group + */ + public ZeroKnowledgeOrProofParser(ECGroup group) { + this.group = group; + } + + /** + * convert ByteString to ECPoint + * @param bs + * @return + */ + public ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + + /** + * inner class + * container for parsed zero knowledge or proof + * constructor is private, can be construct using ZeroKnowledgeOrProofParser.parseOrProof + */ + public class ZeroKnowledgeOrProofContainer{ + public final ECPoint g1,g2,h1,h2; + public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; + public final ECPoint u,v,uTag,vTag; + public final BigInteger c1,c2,z,zTag; + public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + /** + * constructor + * @param orProof + */ + private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ + this.forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(orProof.getG1()) + .setH1(orProof.getH1()) + .setG2(orProof.getG2()) + .setH2(orProof.getH2()) + .setG1Tag(orProof.getG1Tag()) + .setH1Tag(orProof.getH1Tag()) + .setG2Tag(orProof.getG2Tag()) + .setH2Tag(orProof.getH2Tag()) + .setU(orProof.getU()) + .setV(orProof.getV()) + .setUTag(orProof.getUTag()) + .setVTag(orProof.getVTag()) + .build(); + this.g1 = convert2ECPoint(orProof.getG1()); + this.g2 = convert2ECPoint(orProof.getG2()); + this.h1 = convert2ECPoint(orProof.getH1()); + this.h2 = convert2ECPoint(orProof.getH2()); + this.g1Tag = convert2ECPoint(orProof.getG1Tag()); + this.g2Tag = convert2ECPoint(orProof.getG2Tag()); + this.h1Tag = convert2ECPoint(orProof.getH1Tag()); + this.h2Tag = convert2ECPoint(orProof.getH2Tag()); + this.u = convert2ECPoint(orProof.getU()); + this.v = convert2ECPoint(orProof.getV()); + this.uTag = convert2ECPoint(orProof.getUTag()); + this.vTag = convert2ECPoint(orProof.getVTag()); + this.c1 = new BigInteger(orProof.getC1().toByteArray()); + this.c2 = new BigInteger(orProof.getC2().toByteArray()); + this.z = new BigInteger(orProof.getZ().toByteArray()); + this.zTag = new BigInteger(orProof.getZTag().toByteArray()); + } + } } diff --git a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java index 69a1637..fe45e1b 100644 --- a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java +++ b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java @@ -3,19 +3,18 @@ package meerkat.mixer; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.mixing.Mixer; +import meerkat.mixer.mixing.MixerOutput; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; +import meerkat.mixer.verifier.VerifyTable; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Mixer; -import mixer.MixerOutput; -import mixer.Utils; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; -import prover.Prover; -import verifier.Verifier; -import verifier.VerifyTable; import java.io.IOException; import java.security.spec.InvalidKeySpecException; @@ -52,7 +51,7 @@ public class CreateTestVector { randomOracle = new DigestOracle(); verifier = new Verifier(encryptor,randomOracle); prover = new Prover(randomProver,encryptor,randomOracle); - mixer = new Mixer(randomMixer,prover,encryptor,verifier); + mixer = new Mixer(prover,encryptor); // generate n int logN = 10; // + random.nextInt(8) @@ -74,11 +73,11 @@ public class CreateTestVector { List mixerInput = generateMixerInput(); System.out.println("start mixing"); - MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer); System.out.println("mixing ended, start verification"); assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); System.out.println("verification ended, start printing"); - mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); + mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); System.out.println("all done"); } @@ -91,11 +90,11 @@ public class CreateTestVector { List mixerInput = generateMixerInput(); System.out.println("start mixing"); - MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random); System.out.println("mixing ended, start negative verification"); assert (!VerifyTable.verifyTable(verifier,n,mixerOutput)); System.out.println("verification ended, start printing"); - mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); + mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); System.out.println("all done"); } } diff --git a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java index 7755fd4..23eaea4 100644 --- a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java @@ -4,6 +4,9 @@ package meerkat.mixer; * Created by Tzlil on 12/17/2015. */ +import meerkat.mixer.mixing.MixNetwork; +import meerkat.mixer.mixing.RandomPermutation; +import meerkat.mixer.mixing.Switch; import org.junit.Test; import java.util.Arrays; import java.util.Random; diff --git a/mixer/src/test/java/meerkat/mixer/MixingTest.java b/mixer/src/test/java/meerkat/mixer/MixingTest.java index 626060f..f9ec6f8 100644 --- a/mixer/src/test/java/meerkat/mixer/MixingTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixingTest.java @@ -7,6 +7,10 @@ package meerkat.mixer; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.mixing.Mixer; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; +import meerkat.mixer.verifier.VerifyTable; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.factcenter.qilin.primitives.RandomOracle; @@ -15,9 +19,6 @@ import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; -import prover.Prover; -import verifier.Verifier; -import verifier.VerifyTable; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; @@ -49,7 +50,7 @@ public class MixingTest { randomOracle = new DigestOracle(); verifier = new Verifier(encryptor,randomOracle); prover = new Prover(randomProver,encryptor,randomOracle); - mixer = new Mixer(randomMixer,prover,encryptor); + mixer = new Mixer(prover,encryptor); // generate n int logN = 8; // + random.nextInt(8) @@ -75,7 +76,7 @@ public class MixingTest { System.out.println(" start mixing"); long startTime = System.currentTimeMillis(); - meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput); + meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput,randomMixer); long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); diff --git a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java index a87d043..cb7ea3f 100644 --- a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java @@ -5,6 +5,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; @@ -15,8 +17,6 @@ import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; -import prover.Prover; -import verifier.Verifier; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java index 19474f7..8e3b5c1 100644 --- a/mixer/src/test/java/profiling/BigInteger/AddSub.java +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java index e003dea..ebe80f0 100644 --- a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java index 9443347..d0149b0 100644 --- a/mixer/src/test/java/profiling/BigInteger/Modulo.java +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java index dfb8090..4ac913a 100644 --- a/mixer/src/test/java/profiling/BigInteger/Mul.java +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index 92b0c3f..f9b5b2e 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -5,7 +5,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java index 3473430..3d7435f 100644 --- a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Add.java b/mixer/src/test/java/profiling/ECGroup/Add.java index a1cbdfb..e0b5406 100644 --- a/mixer/src/test/java/profiling/ECGroup/Add.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Encode.java b/mixer/src/test/java/profiling/ECGroup/Encode.java index d9577d7..59201e3 100644 --- a/mixer/src/test/java/profiling/ECGroup/Encode.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Mul.java b/mixer/src/test/java/profiling/ECGroup/Mul.java index 2a5573a..836db0e 100644 --- a/mixer/src/test/java/profiling/ECGroup/Mul.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Negate.java b/mixer/src/test/java/profiling/ECGroup/Negate.java index f5b6e15..d190186 100644 --- a/mixer/src/test/java/profiling/ECGroup/Negate.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Rerandomize.java b/mixer/src/test/java/profiling/Rerandomize.java index ea900b5..5a113c9 100644 --- a/mixer/src/test/java/profiling/Rerandomize.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index fe1d407..7d38bf1 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -4,16 +4,16 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.mixer.prover.Prover; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; -import prover.Prover; import java.math.BigInteger; import java.util.Random; From e042779b151ee547adae3b1ebf330e4e29b12b9c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 4 May 2016 17:46:05 +0300 Subject: [PATCH 26/66] Initial code for the Voting Booth. Still missing components: 1. An implementation of the encryptor (currently program crashes when trying to encrypt the PlaintextBallot) 2. The output device implementation should change to a runnable thread (with commands queue as the ui) Also needs to add comments EVERYWHERE. --- .../voting/SystemConsoleOutputDevice.java | 56 --- .../main/java/meerkat/voting/VotingBooth.java | 40 -- .../controller/VotingBoothController.java | 61 +++ .../voting/controller/VotingBoothImpl.java | 363 ++++++++++++++++ .../callbacks/CastOrAuditCallback.java | 47 +++ .../callbacks/ChannelChoiceCallback.java | 43 ++ .../callbacks/ControllerCallback.java | 27 ++ .../controller/callbacks/HaltCallback.java | 32 ++ .../callbacks/NewVoterCallback.java | 32 ++ .../callbacks/OutputDeviceCallback.java | 29 ++ .../controller/callbacks/VotingCallback.java | 40 ++ .../callbacks/WaitForFinishCallback.java | 29 ++ .../controller/commands/AuditCommand.java | 10 + .../controller/commands/CastCommand.java | 10 + .../commands/ChannelChoiceCommand.java | 10 + .../commands/ChannelDeterminedCommand.java | 15 + .../commands/ControllerCommand.java | 19 + .../EncryptAndCommitBallotCommand.java | 12 + .../commands/RestartVotingCommand.java | 8 + .../controller/selector/QuestionSelector.java | 20 + .../selector/SimpleCategoriesData.java | 73 ++++ .../SimpleListCategoriesSelector.java | 121 ++++++ .../selector/SingleChosenAnswer.java | 31 ++ .../voting/encryptor/VBEncryptorImpl.java | 14 + .../{ => encryptor}/VotingBoothEncryptor.java | 12 +- .../{ => output}/BallotOutputDevice.java | 21 +- .../output/SystemConsoleOutputDevice.java | 98 +++++ .../voting/{ => storage}/StorageManager.java | 17 +- .../voting/storage/StorageManagerMockup.java | 67 +++ .../meerkat/voting/ui/SystemConsoleUI.java | 393 ++++++++++++++++++ .../meerkat/voting/ui/TickerTimerTask.java | 25 ++ .../voting/{ => ui}/VotingBoothUI.java | 15 +- .../ui/uicommands/CastOrAuditUICommand.java | 12 + .../ui/uicommands/ChannelChoiceUICommand.java | 22 + .../voting/ui/uicommands/HaltCommand.java | 22 + .../ui/uicommands/RaceVotingUICommand.java | 22 + .../ui/uicommands/StartSessionUICommand.java | 13 + .../voting/ui/uicommands/TickCommand.java | 14 + .../voting/ui/uicommands/UICommand.java | 16 + .../ui/uicommands/WaitForFinishCommand.java | 23 + 40 files changed, 1814 insertions(+), 120 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBooth.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java create mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java rename voting-booth/src/main/java/meerkat/voting/{ => encryptor}/VotingBoothEncryptor.java (79%) rename voting-booth/src/main/java/meerkat/voting/{ => output}/BallotOutputDevice.java (53%) create mode 100644 voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java rename voting-booth/src/main/java/meerkat/voting/{ => storage}/StorageManager.java (51%) create mode 100644 voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java rename voting-booth/src/main/java/meerkat/voting/{ => ui}/VotingBoothUI.java (83%) create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java diff --git a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java deleted file mode 100644 index 7546d53..0000000 --- a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java +++ /dev/null @@ -1,56 +0,0 @@ -package meerkat.voting; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 15/02/16. - */ -public class SystemConsoleOutputDevice implements BallotOutputDevice { - - /* - * Returns the UTF8 decoding of byte-string data - */ - private static String bytesToString(ByteString data) { - return data.toStringUtf8(); - } - - @Override - public void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback) { - - System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " - + bytesToString(encryptedBallot.getData().getData())); - - callback.ballotCommitResult(sessionId, true); - - } - - @Override - public void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback) { - - //TODO: generate standard form for this - System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " - + bytesToString(encryptedBallot.getData().getData())); - - callback.ballotAuditResult(sessionId, true); - - } - - @Override - public void castBallot(long sessionId, VotingBooth.Callback callback) { - - System.out.println("Ballot finalized!"); - - callback.ballotCastResult(sessionId, true); - - } - - @Override - public void cancelBallot(long sessionId, VotingBooth.Callback callback) { - - System.out.println("Ballot cancelled!"); - - callback.ballotCancelResult(sessionId, true); - - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java deleted file mode 100644 index 9ef863c..0000000 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ /dev/null @@ -1,40 +0,0 @@ -package meerkat.voting; - -import meerkat.protobuf.Voting.*; - -/** - * An interface for the controller component of the voting booth - */ -public interface VotingBooth { - - /** - * initialize using the BoothParams protobuf and sett all the different components of the Voting Booth to be recognized by this controller - * @param boothParams - * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection - * @param vbEncryptor the encryption module - * @param vbUI User interface in which the voter chooses his answers - * @param vbStorageManager storage component for handling files and USB sticks - */ - public void init (BoothParams boothParams, - BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, - VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * set the voting questions - * @param questions - */ - public void setBallotQuestions (BallotQuestion[] questions); - - /** - * a synchronous function. Starts running the controller component, and basically run the whole system for voting - */ - public void run (); - - /** - * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system - */ - public void shutDown(); - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java new file mode 100644 index 0000000..ee51f78 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -0,0 +1,61 @@ +package meerkat.voting.controller; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.ui.VotingBoothUI; +import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.output.BallotOutputDevice; +import meerkat.voting.storage.StorageManager; + +import java.util.ArrayList; + + +/** + * An interface for the controller component of the voting booth + */ +public interface VotingBoothController { + + /** + * initialize by setting all the different components of the Voting Booth to be recognized by this controller + * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection + * @param vbEncryptor the encryption module + * @param vbUI User interface in which the voter chooses his answers + * @param vbStorageManager storage component for handling files and USB sticks + */ + public void init (BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); + + /** + * set the voting questions + * @param questions + */ + public void setBallotChannelChoiceQuestions(BallotQuestion[] questions); + public void setBallotChannelChoiceQuestions(ArrayList questions); + + /** + * Set the channel question-selector (the component which matches the ballot questions to each user) + * @param selector the question selector instance + */ + public void setChannelQuestionSelector (QuestionSelector selector); + + /** + * set the voting race questions + * @param questions + */ + public void setBallotRaceQuestions(BallotQuestion[] questions); + public void setBallotRaceQuestions(ArrayList questions); + + /** + * a synchronous function. Starts running the controller component, and basically run the whole system for voting + */ + public void run (); + + /** + * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system + */ + public void shutDown(); + + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java new file mode 100644 index 0000000..fd67cac --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -0,0 +1,363 @@ +package meerkat.voting.controller; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.*; +import meerkat.voting.controller.commands.*; +import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.output.BallotOutputDevice; +import meerkat.voting.storage.StorageManager; +import meerkat.voting.ui.VotingBoothUI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 28/03/16. + */ +public class VotingBoothImpl implements VotingBoothController, Runnable { + + private BallotOutputDevice outputDevice; + private VotingBoothEncryptor encryptor; + private VotingBoothUI ui; + private StorageManager storageManager; + private BallotQuestion[] questionsForChoosingChannel; + private BallotQuestion[] questions; + private QuestionSelector questionSelector; + + private LinkedBlockingQueue queue; + + private Logger logger; + + private ControllerState state; + private boolean shutDownHasBeenCalled; + + protected final int MAX_REQUEST_IDENTIFIER = 100000; + private static int requestCounter = 0; + + private UIElement waitForCommitMessage; + private UIElement waitForAuditMessage; + private UIElement waitForCastMessage; + + + + public VotingBoothImpl () { + logger = LoggerFactory.getLogger(VotingBoothImpl.class); + logger.info("A VotingBoothImpl is constructed"); + shutDownHasBeenCalled = false; + queue = new LinkedBlockingQueue<>(); + + waitForCommitMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build(); + waitForAuditMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build(); + waitForCastMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build(); + + state = new VotingBoothImpl.ControllerState(); + + } + + @Override + public void init(BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager) { + logger.info("init is called"); + this.outputDevice = outputDevice; + this.encryptor = vbEncryptor; + this.ui = vbUI; + this.storageManager = vbStorageManager; + } + + @Override + public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) { + logger.info("setting questions"); + this.questionsForChoosingChannel = questions; + } + + @Override + public void setBallotChannelChoiceQuestions(ArrayList questions) { + BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; + for (int i = 0; i < bqArr.length; ++i) { + bqArr[i] = questions.get(i); + } + setBallotChannelChoiceQuestions(bqArr); + } + + @Override + public void setChannelQuestionSelector(QuestionSelector selector) { + this.questionSelector = selector; + } + + @Override + public void setBallotRaceQuestions(BallotQuestion[] questions) { + logger.info("setting questions"); + this.questions = questions; + } + + @Override + public void setBallotRaceQuestions(ArrayList questions) { + // TODO: why does the toArray method not work?? + //BallotQuestion[] bqArr = (BallotQuestion[])(questions.toArray()); + BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; + for (int i = 0; i < bqArr.length; ++i) { + bqArr[i] = questions.get(i); + } + setBallotRaceQuestions(bqArr); + } + + @Override + public void run() { + logger.info("run command has been called"); + runVotingFlow(); + doShutDown(); + + } + + @Override + public void shutDown() { + logger.info("shutDown command has been called"); + synchronized (this) { + shutDownHasBeenCalled = true; + } + + } + + + + private void runVotingFlow () { + logger.info("entered the voting flow"); + + queue.add(new RestartVotingCommand(generateRequestIdentifier(), state.currentBallotSerialNumber)); + + while (! wasShutDownCalled()) { + try { + ControllerCommand task = queue.take(); + handleSingleTask (task); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from task queue " + e); + } + } + } + + private void doShutDown () { + logger.info("running shutDown"); + } + + private void handleSingleTask (ControllerCommand task) { + if (task instanceof RestartVotingCommand) { + doRestartVoting (); + return; + } + if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) { + String errorMessage = "handleSingleTask: received a task too old. " + + task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; + logger.warn (errorMessage); + return; + } + + if (task instanceof CastCommand) { + doCast(); + return; + } + else if (task instanceof AuditCommand) { + doAudit(); + return; + } + else if (task instanceof ChannelChoiceCommand) { + doChooseChannel(); + return; + } + else if (task instanceof ChannelDeterminedCommand) { + doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); + return; + } + else if (task instanceof EncryptAndCommitBallotCommand) { + doCommit ((EncryptAndCommitBallotCommand)task); + return; + } + else { + String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " + + task.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + /* + Map taskHandlers = new Map<>() { +CaskTask.getClass().getName() : doCast(), +ChannelChoiceCommand.getClass().getName() : doChooseChannel(), +} + + + + */ + + private synchronized boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + private void doRestartVoting () { + queue.clear(); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.NEW_VOTER; + state.currentBallotSerialNumber += 1; + + ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber , this.queue)); + } + + private void doChooseChannel () { + if (state.stateIdentifier == VBState.NEW_VOTER) { + logger.debug("doing chooseChannel"); + state.stateIdentifier = VBState.CHOOSE_CHANNEL; + ui.chooseChannel(this.questionsForChoosingChannel, + new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doChooseChannel: current state is " + state.stateIdentifier); + // ignore this request + } + } + + private void doSetChannelAndAskQuestions (ChannelDeterminedCommand task) { + if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { + logger.debug("doing set channel and ask questions"); + state.stateIdentifier = VBState.ANSWER_QUESTIONS; + BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers; + state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); + state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); + state.stateIdentifier = VBState.ANSWER_QUESTIONS; + ui.askVoterQuestions(state.channelSpecificQuestions, + new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + private void doCommit (EncryptAndCommitBallotCommand task) { + if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { + logger.debug("doing commit"); + state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; + VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); + state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + state.secrets = encryptionAndSecrets.getSecrets(); + ui.notifyVoterToWaitForFinish(waitForCommitMessage, + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); + outputDevice.commitToBallot(state.plaintextBallot, + state.encryptedBallot, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doCommit: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + private void doAudit () { + if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { + logger.debug("doing audit"); + state.stateIdentifier = VBState.FINALIZING; + outputDevice.audit(state.secrets, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(waitForAuditMessage, + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doAudit: current state is " + state.stateIdentifier); + // ignore this request + } + } + + private void doCast () { + if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { + logger.debug("casting ballot"); + state.stateIdentifier = VBState.FINALIZING; + outputDevice.castBallot( + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(waitForCastMessage, + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doCast: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + + + + private enum VBState { + NEW_VOTER, + CHOOSE_CHANNEL, + ANSWER_QUESTIONS, + COMMITTING_TO_BALLOT, + CAST_OR_AUDIT, + FINALIZING + } + + + private class ControllerState { + public VotingBoothImpl.VBState stateIdentifier; + public int channelIdentifier; + public BallotQuestion[] channelSpecificQuestions; + public PlaintextBallot plaintextBallot; + public EncryptedBallot encryptedBallot; + public BallotSecrets secrets; + public int lastRequestIdentifier; + public long currentBallotSerialNumber; + + public ControllerState () { + plaintextBallot = null; + encryptedBallot = null; + secrets = null; + lastRequestIdentifier = -1; + channelIdentifier = -1; + channelSpecificQuestions = null; + currentBallotSerialNumber = 0; + } + + + public void clearPlaintext () { + //TODO: Do we need safe erasure? + plaintextBallot = null; + } + + public void clearCiphertext () { + //TODO: Do we need safe erasure? + encryptedBallot = null; + secrets = null; + } + } + + + private int generateRequestIdentifier() { + ++requestCounter; + if (requestCounter >= MAX_REQUEST_IDENTIFIER) { + requestCounter = 1; + } + return requestCounter; + } + + +} + diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java new file mode 100644 index 0000000..0a5522f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -0,0 +1,47 @@ +package meerkat.voting.controller.callbacks; + + +import meerkat.voting.controller.commands.*; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.ui.VotingBoothUI.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class CastOrAuditCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); + + public CastOrAuditCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert (result instanceof FinalizeBallotChoice); + + if (result == FinalizeBallotChoice.CAST) { + controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else if (result == FinalizeBallotChoice.AUDIT) { + controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("CastOrAuditCallback got an unrecognized response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + } + + @Override + public void onFailure(Throwable t) { + logger.error("CastOrAuditCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} + + + diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java new file mode 100644 index 0000000..c6db8d4 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -0,0 +1,43 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.protobuf.Voting; +import meerkat.voting.controller.commands.ChannelDeterminedCommand; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelChoiceCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); + + public ChannelChoiceCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert (result instanceof Voting.BallotAnswer[]); + if (((Voting.BallotAnswer[])result).length != 0) { + logger.debug("callback for channel choice returned success"); + controllerQueue.add( + new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + } + else { + logger.debug("ChannelChoiceCallback got a cancellation response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("channel choice initiated a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java new file mode 100644 index 0000000..2c33cbc --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -0,0 +1,27 @@ +package meerkat.voting.controller.callbacks; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.voting.controller.commands.ControllerCommand; + +import java.util.concurrent.LinkedBlockingQueue; + +public abstract class ControllerCallback implements FutureCallback { + private final int requestIdentifier; + private final long ballotSerialNumber; + protected LinkedBlockingQueue controllerQueue; + + protected ControllerCallback (int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + this.requestIdentifier = requestId; + this.ballotSerialNumber = ballotSerialNumber; + this.controllerQueue = controllerQueue; + } + + protected int getRequestIdentifier () { + return requestIdentifier; + } + protected long getBallotSerialNumber () { + return ballotSerialNumber; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java new file mode 100644 index 0000000..c251a0f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java @@ -0,0 +1,32 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 21/04/16. + */ +public class HaltCallback extends ControllerCallback{ + protected final static Logger logger = LoggerFactory.getLogger(HaltCallback.class); + + public HaltCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + + @Override + public void onSuccess(Object result) { + throw new UnsupportedOperationException("HaltCallback: onSuccess: There cannot be a successful return for this task. Returned value is " + result); + } + + @Override + public void onFailure(Throwable t) { + logger.error("Halting initiated a failure: " + t); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java new file mode 100644 index 0000000..bdb53c3 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -0,0 +1,32 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ChannelChoiceCommand; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class NewVoterCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); + + public NewVoterCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + logger.debug("callback for new voting returned success"); + assert v==null; + controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("New voting session got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java new file mode 100644 index 0000000..81a14c4 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class OutputDeviceCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); + + public OutputDeviceCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + assert v instanceof Void; + } + + @Override + public void onFailure(Throwable t) { + logger.error("WaitForFinishCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java new file mode 100644 index 0000000..5e0cc1a --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -0,0 +1,40 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.protobuf.Voting; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class VotingCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); + + public VotingCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert result instanceof Voting.BallotAnswer[]; + if (((Voting.BallotAnswer[])result).length != 0) { + logger.debug("callback for voting returned success"); + controllerQueue.add( + new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + } + else { + logger.debug("VotingCallback got a cancellation response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("voting initiated a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java new file mode 100644 index 0000000..d56327d --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class WaitForFinishCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); + + public WaitForFinishCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + assert v instanceof Void; + } + + @Override + public void onFailure(Throwable t) { + logger.error("WaitForFinishCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java new file mode 100644 index 0000000..d2c99f2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class AuditCommand extends ControllerCommand { + public AuditCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java new file mode 100644 index 0000000..0621efb --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class CastCommand extends ControllerCommand { + public CastCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java new file mode 100644 index 0000000..f555e4b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelChoiceCommand extends ControllerCommand { + public ChannelChoiceCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java new file mode 100644 index 0000000..8fefbe7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -0,0 +1,15 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelDeterminedCommand extends ControllerCommand { + public Voting.BallotAnswer[] channelChoiceAnswers; + + public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + super(requestIdentifier, ballotSerialNumber); + channelChoiceAnswers = answers; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java new file mode 100644 index 0000000..5bfc5c2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java @@ -0,0 +1,19 @@ +package meerkat.voting.controller.commands; + +public abstract class ControllerCommand { + protected final int requestIdentifier; + protected final long ballotSerialNumber; + + protected ControllerCommand(int requestIdentifier, long ballotSerialNumber) { + this.requestIdentifier = requestIdentifier; + this.ballotSerialNumber = ballotSerialNumber; + } + + public long getBallotSerialNumber () { + return this.ballotSerialNumber; + } + + public int getRequestIdentifier () { + return this.requestIdentifier; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java new file mode 100644 index 0000000..bad2ff7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -0,0 +1,12 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting; + +public class EncryptAndCommitBallotCommand extends ControllerCommand { + public Voting.BallotAnswer[] votingAnswers; + + public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + super(requestIdentifier, ballotSerialNumber); + votingAnswers = answers; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java new file mode 100644 index 0000000..57906d2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java @@ -0,0 +1,8 @@ +package meerkat.voting.controller.commands; + + +public class RestartVotingCommand extends ControllerCommand { + public RestartVotingCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java new file mode 100644 index 0000000..3fd2188 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -0,0 +1,20 @@ +package meerkat.voting.controller.selector; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 02/05/16. + */ +public abstract class QuestionSelector { + + protected Object selectionData; + protected BallotQuestion[] allBallotQuestions; + + public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { + this.selectionData = selectionData; + this.allBallotQuestions = allBallotQuestions; + } + + public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers); + public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers); +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java new file mode 100644 index 0000000..83ae516 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java @@ -0,0 +1,73 @@ +package meerkat.voting.controller.selector; + +import java.util.HashMap; +import java.lang.Math; + +/** + * Created by hai on 02/05/16. + */ +public class SimpleCategoriesData { + + private int[] sharedDefaults; + private HashMap questionsSelections; + private int maxQuestionNumber; + + public SimpleCategoriesData() { + sharedDefaults = new int[0]; + questionsSelections = new HashMap(); + maxQuestionNumber = -1; + } + + public void setSharedDefaults(int[] sharedDefaultsIndices) { + this.sharedDefaults = sharedDefaultsIndices; + maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices)); + } + + public int[] getSharedDefaults() { + return sharedDefaults; + } + + public void setItem(SingleChosenAnswer key, int[] questionIndices) { + questionsSelections.put(key, questionIndices); + maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices)); + } + + public int[] getItem(SingleChosenAnswer key) { + return questionsSelections.get(key); + } + + public int getMaxQuestionNumber() { + return maxQuestionNumber; + } + + + private static int maxInt(int[] arr) { + int m = -1; + for (int i: arr) { + m = Math.max(i , m); + } + return m; + } + + public String toString () { + String s = "SimpleCategoriesData:\n"; + s += "shared : " + arrayToString(sharedDefaults) + "\n"; + s += "map : \n"; + for (SingleChosenAnswer key : questionsSelections.keySet()) { + s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n"; + } + return s; + } + + private String arrayToString (int[] a) { + if (a.length == 0) { + return "[]"; + } + String s = "[" + a[0]; + for (int i = 1; i < a.length; ++i) { + s += ", " + a[i]; + } + return s + "]"; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java new file mode 100644 index 0000000..31911e6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -0,0 +1,121 @@ +package meerkat.voting.controller.selector; + +import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; + +/** + * Created by hai on 02/05/16. + */ +public class SimpleListCategoriesSelector extends QuestionSelector { + protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + private boolean[] isSelected; + + public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { + super(selectionData, allBallotQuestions); + initializeAttributes (allBallotQuestions); + } + + public SimpleListCategoriesSelector(Object selectionData, ArrayList allBallotQuestions) { + super(selectionData, null); + BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()]; + for (int i = 0; i < questionsArr.length; ++i) { + questionsArr[i] = allBallotQuestions.get(i); + } + initializeAttributes (questionsArr); + } + + private void initializeAttributes (BallotQuestion[] allBallotQuestions) { + assert selectionData instanceof SimpleCategoriesData; + this.allBallotQuestions = allBallotQuestions; + SimpleCategoriesData data = (SimpleCategoriesData) selectionData; + int maxQuestionNumber = data.getMaxQuestionNumber(); + int length = allBallotQuestions.length; + if (maxQuestionNumber >= length) { + String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + length + " questions totally"; + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + isSelected = new boolean[allBallotQuestions.length]; + } + + + @Override + public int getChannelIdentifier(BallotAnswer[] channelChoiceAnswers) { + return 0; + } + + @Override + public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + java.util.Arrays.fill(isSelected, false); + markSelected(data.getSharedDefaults()); + markSelectionsOfVoterChannelChoice (channelChoiceAnswers); + int[] questionIndices = extractSelectedIndices(); + BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length]; + for (int i = 0; i < questionIndices.length; ++i) { + selectedQuestions[i] = allBallotQuestions[questionIndices[i]]; + } + return selectedQuestions; + } + + private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + for (int q = 0; q < channelChoiceAnswers.length; ++q) { + BallotAnswer ballotAnswer = channelChoiceAnswers[q]; + assertAnswerLengthIsOne(ballotAnswer, q); + SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0)); + assertKeyInSelectionData(key); + markSelected(data.getItem(key)); + } + } + + private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { + if (ballotAnswer.getAnswerCount() != 1) { + String errorMessage = "SimpleListCategoriesSelector expects a single answer for every channel choice question\n"; + errorMessage += "Answer to question number " + (questionNumber+1) + " is"; + for (long i : ballotAnswer.getAnswerList()) { + errorMessage += " " + i; + } + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + } + + private void assertKeyInSelectionData(SingleChosenAnswer key) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + int[] questionListToAdd = data.getItem(key); + if (null == questionListToAdd) { + String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + key.answerNumber + " for question number " + key.questionNumber; + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + } + + private void markSelected (int[] questionIndices) { + for (int i: questionIndices) { + isSelected[i] = true; + } + } + + private int[] extractSelectedIndices() { + int nSelected = 0; + for (boolean b: isSelected) { + if (b) { + nSelected++; + } + } + int[] res = new int[nSelected]; + int currIndex = 0; + for (int questionNumber = 0; questionNumber < isSelected.length; ++questionNumber) { + if (isSelected[questionNumber]) { + res[currIndex] = questionNumber; + currIndex++; + } + } + return res; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java new file mode 100644 index 0000000..fad377b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java @@ -0,0 +1,31 @@ +package meerkat.voting.controller.selector; + +/** + * Created by hai on 02/05/16. + */ +public class SingleChosenAnswer { + public int questionNumber; + public long answerNumber; + + public SingleChosenAnswer(int questionNumber, long answerNumber) { + this.questionNumber = questionNumber; + this.answerNumber = answerNumber; + } + + public String toString() { + return "SingleChosenAnswer(" + questionNumber + ", " + answerNumber + ")"; + } + + public boolean equals (Object other) { + if (!(other instanceof SingleChosenAnswer)) { + return false; + } + SingleChosenAnswer o = (SingleChosenAnswer)other; + return (o.questionNumber == this.questionNumber) && (o.answerNumber == this.answerNumber); + } + + @Override + public int hashCode () { + return questionNumber*1000 + (int)answerNumber; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java new file mode 100644 index 0000000..51ffef0 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java @@ -0,0 +1,14 @@ +package meerkat.voting.encryptor; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 26/04/16. + */ +public class VBEncryptorImpl implements VotingBoothEncryptor { + + @Override + public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) { + throw new UnsupportedOperationException(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java similarity index 79% rename from voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java rename to voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java index cc9b7bc..e9a885f 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java @@ -1,6 +1,5 @@ -package meerkat.voting; +package meerkat.voting.encryptor; -import com.sun.org.apache.xml.internal.security.encryption.EncryptedType; import meerkat.protobuf.Voting.*; /** @@ -20,8 +19,13 @@ public interface VotingBoothEncryptor { this.secrets = secrets; } - public EncryptedBallot getEncryptedBallot () { return encryptedBallot; } - public BallotSecrets getSecrets() { return secrets; } + public EncryptedBallot getEncryptedBallot () { + return encryptedBallot; + } + + public BallotSecrets getSecrets() { + return secrets; + } } diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java similarity index 53% rename from voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java rename to voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 0199523..8d1f7f1 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -1,4 +1,4 @@ -package meerkat.voting; +package meerkat.voting.output; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; @@ -12,28 +12,29 @@ public interface BallotOutputDevice { /** * Output the encrypted ballot. This is a commitment before voter chooses casting or auditing * @param encryptedBallot - the encrypted ballot to commit to - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void commitToBallot(EncryptedBallot encryptedBallot, FutureCallback callback); + public void commitToBallot(PlaintextBallot plaintextBallot, + EncryptedBallot encryptedBallot, + FutureCallback callback); /** * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. - * @param encryptedBallot - the encrypted ballot * @param ballotSecrets - the secrtes of the encryption - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void audit(EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, FutureCallback callback); + public void audit(BallotSecrets ballotSecrets, FutureCallback callback); /** * Voter chose 'cast'. Finalize the ballot for use in the polling station - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void castBallot(FutureCallback callback); + public void castBallot(FutureCallback callback); /** * Cancelling the current ballot. This clears the state of the OutputDevice if the implementation has any such state. - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void cancelBallot(FutureCallback callback); + public void cancelBallot(FutureCallback callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java new file mode 100644 index 0000000..e1556d6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -0,0 +1,98 @@ +package meerkat.voting.output; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A toy OutputDevice class + * outputs everything simply to the System console + */ +public class SystemConsoleOutputDevice implements BallotOutputDevice { + + private Logger logger; + + public SystemConsoleOutputDevice () { + logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); + logger.info("A SystemConsoleOutputDevice is constructed"); + } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + + @Override + public void commitToBallot(PlaintextBallot plaintextBallot, + EncryptedBallot encryptedBallot, + FutureCallback callback) { + logger.debug("entered method commitToBallot"); + long plaintextSerialNumber = plaintextBallot.getSerialNumber(); + System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + long encryptedSerialNumber = encryptedBallot.getSerialNumber(); + System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); + if (plaintextSerialNumber != encryptedSerialNumber) { + logger.error("plaintext and encryption serial numbers do not match!! plaintext# = " + + plaintextSerialNumber + ", ciphertext# = " + encryptedSerialNumber); + } + ByteString encryptedData = encryptedBallot.getData().getData(); + System.out.println(bytesToString(encryptedData)); + callback.onSuccess(null); + } + + @Override + public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { + logger.debug("entered method audit"); + System.out.println("Auditing"); + printPlaintextBallot (ballotSecrets.getPlaintextBallot()); + printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); + printRandomnessGenerationProof (ballotSecrets.getProof()); + callback.onSuccess(null); + } + + private void printPlaintextBallot (PlaintextBallot plaintextBallot) { + long plaintextSerialNumber = plaintextBallot.getSerialNumber(); + System.out.println("Plaintext serial number = " + plaintextSerialNumber); + + System.out.println("Answers = "); + for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) { + String printableAnswer = ""; + for (long n : ballotAnswer.getAnswerList()) { + printableAnswer += n + " "; + } + System.out.println(printableAnswer); + } + } + + private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) { + System.out.println("Encryption Randomness = "); + ByteString data = encryptionRandomness.getData(); + System.out.println(bytesToString(data)); + } + + private void printRandomnessGenerationProof (RandomnessGenerationProof proof) { + System.out.println("Proof of randomness generation:"); + ByteString data = proof.getData(); + System.out.println(bytesToString(data)); + } + + + @Override + public void castBallot(FutureCallback callback) { + logger.debug("entered method castBallot"); + System.out.println("Ballot finalized for casting!"); + callback.onSuccess(null); + } + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("entered method cancelBallot"); + System.out.println("Ballot cancelled!"); + callback.onSuccess(null); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java similarity index 51% rename from voting-booth/src/main/java/meerkat/voting/StorageManager.java rename to voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index 0fd18ca..9bf7764 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -1,7 +1,9 @@ -package meerkat.voting; +package meerkat.voting.storage; import meerkat.protobuf.Voting.*; +import java.io.IOException; + /** * An interface for the storage component of the voting booth */ @@ -14,8 +16,17 @@ public interface StorageManager { public boolean isAdminHardwareKeyInserted(); /** - * load the election params from a file. + * load the election params from the storage. * @return the current election params + * @throws IOException */ - public ElectionParams readElectionParams (); + public ElectionParams readElectionParams () throws IOException; + + /** + * write the election parameters protobuf to the storage + * @param params ElectionParams protobuf to save + * @throws IOException + */ + public void writeElectionParams(ElectionParams params) throws IOException; + } diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java new file mode 100644 index 0000000..23c89cf --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -0,0 +1,67 @@ +package meerkat.voting.storage; + +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * A mockup for the StorageManager interface + * Currently keeps the ElectionParams in a file in the user's home-directory + */ +public class StorageManagerMockup implements StorageManager { + + private boolean adminHardwareKeyInserted; + private Logger logger; + private String electionParamFullFilename = "~/meerkat_election_params_tempfile.dat"; + + public StorageManagerMockup () { + logger = LoggerFactory.getLogger(StorageManagerMockup.class); + logger.info("A StorageManagerMockup is constructed"); + this.adminHardwareKeyInserted = false; + } + + @Override + public boolean isAdminHardwareKeyInserted() { + logger.info("Entered method isAdminHardwareKeyInserted"); + logger.warn("isAdminHardwareKeyInserted is not yet fully implemented. It does not check the file system. " + + "Rather it just returns a private boolean member"); + return adminHardwareKeyInserted; + } + + @Override + public ElectionParams readElectionParams() throws IOException { + logger.info("Entered method readElectionParams"); + ElectionParams params; + try { + FileInputStream inputStream = new FileInputStream(electionParamFullFilename); + params = ElectionParams.parseFrom(inputStream); + inputStream.close(); + logger.info ("Successfully read election parameter protobuf from a file"); + } + catch (IOException e) { + logger.error("Could not read from the election parameter file: '" + electionParamFullFilename + "'."); + throw e; + } + return params; + } + + @Override + public void writeElectionParams(ElectionParams params) throws IOException { + logger.info("Entered method writeElectionParams"); + try { + FileOutputStream output = new FileOutputStream(electionParamFullFilename); + params.writeTo(output); + output.close(); + logger.info ("Successfully wrote election parameter protobuf to a file"); + } + catch (IOException e) { + logger.error("Could not write to the election parameter file: '" + electionParamFullFilename + "'."); + throw e; + } + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java new file mode 100644 index 0000000..4b6486e --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -0,0 +1,393 @@ +package meerkat.voting.ui; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Date; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.concurrent.LinkedBlockingQueue; + +import meerkat.voting.controller.callbacks.*; +import meerkat.voting.ui.uicommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.System.in; + + +public class SystemConsoleUI implements VotingBoothUI, Runnable { + + private BufferedReader bufferedReader; + private LinkedBlockingQueue queue; + private final Logger logger; + private final int tickDurationInMillisec = 10; + private Date startWaitingTime; + + + public SystemConsoleUI() { + logger = LoggerFactory.getLogger(SystemConsoleUI.class); + logger.info("A VB UI console is constructed"); + queue = new LinkedBlockingQueue<>(); + bufferedReader = new BufferedReader(new InputStreamReader(in)); + + startWaitingTime = null; + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + } + + + public void run () { + logger.info("entered the voting flow"); + while (true) { + try { + UICommand task = queue.take(); + handleSingleTask (task); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from task queue " + e); + } + } + } + + + private void handleSingleTask (UICommand task) { + if (!(task instanceof TickCommand)) { + if (startWaitingTime != null) { + stopWaiting(); + } + } + + if (task instanceof StartSessionUICommand) { + doShowWelcomeScreen((StartSessionUICommand)task); + return; + } + else if (task instanceof ChannelChoiceUICommand) { + doAskChannelChoiceQuestions((ChannelChoiceUICommand)task); + return; + } + else if (task instanceof RaceVotingUICommand) { + doAskVotingQuestions((RaceVotingUICommand)task); + return; + } + else if (task instanceof CastOrAuditUICommand) { + doCastOrAudit ((CastOrAuditUICommand)task); + return; + } + else if (task instanceof HaltCommand) { + doHalt((HaltCommand)task); + return; + } + else if (task instanceof WaitForFinishCommand) { + doWaitForFinish((WaitForFinishCommand)task); + return; + } + else if (task instanceof TickCommand) { + doTick (); + return; + } + else { + String errorMessage = "handleSingleTask: unknown type of UICommand received: " + + task.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + + @Override + public void startNewVoterSession(FutureCallback callback) { + logger.debug("UI interface call to startNewVoterSession"); + queue.add(new StartSessionUICommand((ControllerCallback)callback)); + } + + private void doShowWelcomeScreen(StartSessionUICommand task) { + logger.debug("UI entered doShowWelcomeScreen"); + System.out.println("Welcome, new voter!"); + waitForEnter(null); + ControllerCallback callback = task.getCallback(); + assert (callback instanceof NewVoterCallback); + ((NewVoterCallback)callback).onSuccess(null); + } + + private void stopWaiting () { + System.out.println (); + startWaitingTime = null; + + } + private void waitForEnter(String message) { + if (message != null) { + System.out.println(message); + } + System.out.println("\nPress ENTER to proceed.\n"); + String t = null; + while (t == null) { + try { + t = readInputLine(); + } + catch (IOException e) { + String errorMessage = "waitForEnter: threw an IOException: " + e; + logger.error(errorMessage); + System.err.println(errorMessage); + } + } + } + + @Override + public void chooseChannel(BallotQuestion[] questions, FutureCallback callback) { + logger.debug("UI interface call to chooseChannel"); + ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + queue.add(task); + } + + private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) { + logger.debug("UI: doAskChannelChoiceQuestions"); + System.out.println("Showing questions for choosing channel:\n"); + try { + BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); + task.getCallback().onSuccess(answers); + } + catch (IOException e) { + String errorMessage = "Channel choice failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + task.getCallback().onFailure(e); + } + } + + @Override + public void askVoterQuestions(BallotQuestion[] questions, FutureCallback callback) { + logger.debug("UI interface call to chooseChannel"); + queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); + } + + private void doAskVotingQuestions (RaceVotingUICommand task) { + logger.debug("UI: doAskVotingQuestions"); + System.out.println("Showing questions for race voting:\n"); + try { + BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); + task.getCallback().onSuccess(answers); + } + catch (IOException e) { + String errorMessage = "Asking voting questions failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + task.getCallback().onFailure(e); + } + } + + @Override + public void castOrAudit(FutureCallback callback) { + logger.debug("UI interface call to castOrAudit"); + queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); + } + + private void doCastOrAudit(CastOrAuditUICommand task) { + logger.debug("UI entered doCastOrAudit"); + System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); + + FinalizeBallotChoice fChoice; + + try { + String s = readInputLine(); + if (s.equals("cast") || s.equals("c")) { + fChoice = FinalizeBallotChoice.CAST; + } + else if (s.equals("audit") || s.equals("a")) { + fChoice = FinalizeBallotChoice.AUDIT; + } + else { + throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'"); + } + ControllerCallback callback = task.getCallback(); + assert (callback instanceof CastOrAuditCallback); + ((CastOrAuditCallback)callback).onSuccess(fChoice); + } + catch (IllegalArgumentException|IOException e) { + String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e; + logger.error(errorMessage); + task.getCallback().onFailure(e); + } + } + + + @Override + public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { + logger.debug("UI interface call to notifyVoterToWaitForFinish"); + queue.add(new WaitForFinishCommand(message, (ControllerCallback)callback)); + } + + public void doWaitForFinish (WaitForFinishCommand task) { + logger.debug("UI entered doWaitForFinish"); + + startWaitingTime = new Date(); + + UIElement message = task.getMessage(); + String messageString; + if (message.getType() != UIElementDataType.TEXT) { + messageString = "Default message: encountered an error. System halting"; + } else { + messageString = bytesToString(message.getData()); + } + System.out.println(messageString); + System.out.print ("Waiting : ."); + } + + @Override + public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageAndHalt"); + queue.add(new HaltCommand(errorMessage, (ControllerCallback)callback)); + } + + private void doHalt (HaltCommand task) { + logger.debug("UI entered doHalt"); + + UIElement errorMessage = task.getErrorMessage(); + String errorMessageString; + if (errorMessage.getType() != UIElementDataType.TEXT) { + errorMessageString = "Default message: encountered an error. System halting"; + } else { + errorMessageString = bytesToString(errorMessage.getData()); + } + System.out.println(errorMessageString); + + while (true) { + try { + wait(); + } catch (InterruptedException e) { + logger.error("UI halt has been interrupted. Details: " + e); + ControllerCallback callback = task.getCallback(); + assert callback instanceof HaltCallback; + ((HaltCallback) callback).onFailure(e); + } + } + } + + + @Override + public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { + throw new UnsupportedOperationException(); + } + + private void doTick () { + if (startWaitingTime != null) { + System.out.print ("."); // still waiting + } + } + + private String readInputLine() throws IOException{ + String s; + try { + s = this.bufferedReader.readLine(); + if (null == s) { + throw new IOException(); + } + } catch (IOException e) { + String errorMessage = "readInputLine: some error with reading input from console. details: " + e; + logger.error(errorMessage); + throw new IOException(e); + } + return s; + } + + + private void assertQuestionsAreValid (BallotQuestion[] questions) { + for (int index = 0; index < questions.length; ++index) { + BallotQuestion question = questions[index]; + if (question.getIsMandatory()) { + String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory"; + logger.error(errorMessage); + throw new UnsupportedOperationException(errorMessage); + } + if (!isQuestionOnlyText(question)) { + String errorMessage = "askVoterQuestions: question number " + index + " is not only text"; + logger.error(errorMessage); + throw new UnsupportedOperationException(errorMessage); + } + } + } + + private BallotAnswer[] askVoterForAnswers(BallotQuestion[] questions) throws IOException { + + assertQuestionsAreValid (questions); + + BallotAnswer answers[] = new BallotAnswer[questions.length]; + int index = 0; + while (index < questions.length) { + BallotQuestion question = questions[index]; + System.out.println("Question number " + index); + showQuestionOnScreen(question); + + System.out.println("UI screen: Enter your answer. You can also type '(b)ack' or '(c)ancel' or '(s)kip"); + String s = readInputLine(); + + if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { + return null; + } + else if (s.equals("back") || s.equals("b")) { + --index; + } + else if (s.equals("skip") || s.equals("s")) { + answers[index] = translateStringAnswerToProtoBufMessageAnswer(""); + ++index; + } + else { + answers[index] = translateStringAnswerToProtoBufMessageAnswer(s); + ++index; + } + } + return answers; + } + + //show question on the screen for the voter + private void showQuestionOnScreen(BallotQuestion question) { + if (!isQuestionOnlyText(question)) { + System.err.println("debug: an element in question is not of TEXT type"); + throw new UnsupportedOperationException(); + } + + System.out.println("Question text: " + bytesToString(question.getQuestion().getData())); + System.out.println("Description: " + bytesToString(question.getDescription().getData())); + int answerIndex = 0; + for (UIElement answer : question.getAnswerList()) { + ++answerIndex; + System.out.println("Answer " + answerIndex + ": " + bytesToString(answer.getData())); + } + } + + private boolean isQuestionOnlyText (BallotQuestion question) { + boolean isText = true; + if (question.getQuestion().getType() != UIElementDataType.TEXT + || question.getDescription().getType() != UIElementDataType.TEXT) { + isText = false; + } + for (UIElement answer : question.getAnswerList()) { + if (answer.getType() != UIElementDataType.TEXT) { + isText = false; + } + } + return isText; + } + + + private BallotAnswer translateStringAnswerToProtoBufMessageAnswer(String s) { + BallotAnswer.Builder bab = BallotAnswer.newBuilder(); + StringTokenizer st = new StringTokenizer(s); + while (st.hasMoreTokens()) { + bab.addAnswer(Integer.parseInt(st.nextToken())); + } + return bab.build(); + } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java new file mode 100644 index 0000000..a293e5f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -0,0 +1,25 @@ +package meerkat.voting.ui; + +import meerkat.voting.ui.uicommands.TickCommand; +import meerkat.voting.ui.uicommands.UICommand; + +import java.util.TimerTask; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 25/04/16. + */ +class TickerTimerTask extends TimerTask { + private LinkedBlockingQueue uiQueue; + public TickerTimerTask (LinkedBlockingQueue uiQueue) { + this.uiQueue = uiQueue; + } + + @Override + public void run() { + UICommand t = uiQueue.peek(); + if ((t != null) && !(t instanceof TickCommand)) { + uiQueue.add(new TickCommand(null)); + } + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java similarity index 83% rename from voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java rename to voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index c2ccfea..ae96f7b 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -1,30 +1,31 @@ -package meerkat.voting; +package meerkat.voting.ui; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; + /** * An interface for the user interface component of the voting booth */ public interface VotingBoothUI { - public static enum FinalizeBallotChoice { + public enum FinalizeBallotChoice { CAST, AUDIT } /** * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning - * @param callback - a boolean future callback to return success when done + * @param callback - a boolean future callback to return when done */ - public void startNewVoterSession (FutureCallback callback); + public void startNewVoterSession (FutureCallback callback); /** * Present a question to the voter to decide on his voting channel. - * @param question a question to determine the right voting channel for this voter - * @param callback that's where we store the channel for the current voter + * @param questions questions to determine the right voting channel for this voter + * @param callback that's where we store the answers to decide channel upon for the current voter */ - public void chooseChannel (BallotQuestion question, FutureCallback callback); + public void chooseChannel (BallotQuestion[] questions, FutureCallback callback); /** * Presents the set of questions to the voter. Collect all his responses. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java new file mode 100644 index 0000000..993f64b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -0,0 +1,12 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 21/04/16. + */ +public class CastOrAuditUICommand extends UICommand { + public CastOrAuditUICommand(ControllerCallback callback) { + super(callback); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java new file mode 100644 index 0000000..22d2ff3 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class ChannelChoiceUICommand extends UICommand { + + private final BallotQuestion[] questions; + + public ChannelChoiceUICommand(BallotQuestion[] questions, ControllerCallback callback) + { + super(callback); + this.questions = questions; + } + + public BallotQuestion[] getQuestions () { + return this.questions; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java new file mode 100644 index 0000000..5213354 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class HaltCommand extends UICommand { + + private final UIElement errorMessage; + + public HaltCommand(UIElement errorMessage, ControllerCallback callback) + { + super(callback); + this.errorMessage = errorMessage; + } + + public UIElement getErrorMessage () { + return this.errorMessage; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java new file mode 100644 index 0000000..31d2706 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class RaceVotingUICommand extends UICommand { + + private final BallotQuestion[] questions; + + public RaceVotingUICommand(BallotQuestion[] questions, ControllerCallback callback) + { + super(callback); + this.questions = questions; + } + + public BallotQuestion[] getQuestions () { + return this.questions; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java new file mode 100644 index 0000000..f1bc146 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -0,0 +1,13 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class StartSessionUICommand extends UICommand { + + public StartSessionUICommand(ControllerCallback callback) { + super(callback); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java new file mode 100644 index 0000000..3192f4c --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class TickCommand extends UICommand { + + public TickCommand(ControllerCallback callback) { + super(callback); + assert null == callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java new file mode 100644 index 0000000..b22fdef --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +//TODO: make this class generic +public abstract class UICommand { + protected final ControllerCallback callback; + + protected UICommand(ControllerCallback callback) { + this.callback = callback; + } + + public ControllerCallback getCallback () { + return this.callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java new file mode 100644 index 0000000..fe9b1cc --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java @@ -0,0 +1,23 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ + +public class WaitForFinishCommand extends UICommand { + + private final UIElement message; + + public WaitForFinishCommand(UIElement message, ControllerCallback callback) + { + super(callback); + this.message = message; + } + + public UIElement getMessage () { + return this.message; + } +} From c04ed42dcaee9d5900978fdca9404b9de2fe2bf4 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 4 May 2016 17:52:01 +0300 Subject: [PATCH 27/66] possible future protobufs for handling category channel selection. Summary: The initial code for the voting booth. Some things are still missing: 1. comments EVERYWHERE 2. an implementation for the encryptor (program crashes when trying to encrypt PlaintexBallot) 3. the OutputDevice class should become a thread, (runnable with a queue of commands as the UI component) Test Plan: Currently only simply run it with another main class. Reviewers: arbel.peled Differential Revision: https://proj-cs.idc.ac.il/D3 --- meerkat-common/src/main/proto/meerkat/voting.proto | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 8b49ca9..8ece676 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -39,6 +39,17 @@ message BallotQuestion { } +message QuestionCluster { + UIElement cluster_description = 1; + repeated int32 question_index = 2; + +} + +message Channel { + UIElement channel_description = 1; + repeated int32 cluster_index = 2; + +} // An answer to a specific ballot question. // The answer is a vector of signed integers, From 94f3920e6db9443cb1950859ba7e1df2f4544fac Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 23 May 2016 14:43:01 +0300 Subject: [PATCH 28/66] Many fixes, some are still only in temporary phase, according to what Arbel told me to do so far. --- .../voting/controller/SystemMessages.java | 84 +++++++ .../controller/VotingBoothController.java | 16 +- .../voting/controller/VotingBoothImpl.java | 217 ++++++++---------- .../callbacks/CastOrAuditCallback.java | 20 +- .../callbacks/ChannelChoiceCallback.java | 24 +- .../callbacks/ControllerCallback.java | 14 +- .../ErrorMessageRestartCallback.java | 29 +++ .../controller/callbacks/HaltCallback.java | 32 --- .../callbacks/NewVoterCallback.java | 9 +- .../callbacks/OutputDeviceCallback.java | 11 +- .../controller/callbacks/VotingCallback.java | 21 +- .../callbacks/WaitForFinishCallback.java | 11 +- .../commands/ChannelDeterminedCommand.java | 7 +- .../EncryptAndCommitBallotCommand.java | 12 +- .../commands/ReportErrorCommand.java | 16 ++ .../controller/commands/ShutDownCommand.java | 10 + .../controller/selector/QuestionSelector.java | 16 +- .../controller/selector/SelectionData.java | 7 + .../selector/SimpleCategoriesData.java | 60 +++-- .../SimpleListCategoriesSelector.java | 108 +++++---- .../selector/SingleChosenAnswer.java | 31 --- .../meerkat/voting/ui/SystemConsoleUI.java | 168 +++++++------- .../java/meerkat/voting/ui/VotingBoothUI.java | 8 +- .../ui/uicommands/CastOrAuditUICommand.java | 2 +- .../ui/uicommands/ChannelChoiceUICommand.java | 10 +- .../ui/uicommands/FatalErrorUICommand.java | 28 +++ .../voting/ui/uicommands/HaltCommand.java | 22 -- .../ui/uicommands/RaceVotingUICommand.java | 10 +- .../ui/uicommands/StartSessionUICommand.java | 2 +- .../voting/ui/uicommands/TickCommand.java | 2 +- .../voting/ui/uicommands/UICommand.java | 2 +- ...mmand.java => WaitForFinishUICommand.java} | 6 +- 32 files changed, 571 insertions(+), 444 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java rename voting-booth/src/main/java/meerkat/voting/ui/uicommands/{WaitForFinishCommand.java => WaitForFinishUICommand.java} (60%) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java new file mode 100644 index 0000000..ee6b506 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java @@ -0,0 +1,84 @@ +package meerkat.voting.controller; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 18/05/16. + */ +final public class SystemMessages { + + private SystemMessages() { + // This is a static class. No instantiation of this is needed. + } + + public static UIElement getWaitForCommitMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build(); + } + + public static UIElement getWaitForAuditMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build(); + } + + public static UIElement getWaitForCastMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build(); + } + + public static UIElement getFatalForceRestartMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Fatal error: Internal controller queue received unrecognized command. Force restarting the voting process.")) + .build(); + } + + public static UIElement getRestartVotingButton() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Restart voting")) + .build(); + } + + public static UIElement getUnrecognizedFinalizeResponseMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) + .build(); + } + + public static UIElement getUnsuccessfulChannelChoiceMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) + .build(); + } + + public static UIElement getOutputDeviceFailureMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) + .build(); + } + + public static UIElement getUnsuccessfulVotingMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) + .build(); + } + + public static UIElement getSomethingWrongMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) + .build(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index ee51f78..057f13d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -8,12 +8,13 @@ import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import java.util.ArrayList; +import java.util.List; /** * An interface for the controller component of the voting booth */ -public interface VotingBoothController { +public interface VotingBoothController extends Runnable{ /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller @@ -31,8 +32,7 @@ public interface VotingBoothController { * set the voting questions * @param questions */ - public void setBallotChannelChoiceQuestions(BallotQuestion[] questions); - public void setBallotChannelChoiceQuestions(ArrayList questions); + public void setBallotChannelChoiceQuestions(List questions); /** * Set the channel question-selector (the component which matches the ballot questions to each user) @@ -44,18 +44,12 @@ public interface VotingBoothController { * set the voting race questions * @param questions */ - public void setBallotRaceQuestions(BallotQuestion[] questions); - public void setBallotRaceQuestions(ArrayList questions); - - /** - * a synchronous function. Starts running the controller component, and basically run the whole system for voting - */ - public void run (); + public void setBallotRaceQuestions(List questions); /** * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system */ - public void shutDown(); + public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index fd67cac..cd53f65 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -12,20 +12,20 @@ import meerkat.voting.ui.VotingBoothUI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; /** * Created by hai on 28/03/16. */ -public class VotingBoothImpl implements VotingBoothController, Runnable { +public class VotingBoothImpl implements VotingBoothController { private BallotOutputDevice outputDevice; private VotingBoothEncryptor encryptor; private VotingBoothUI ui; private StorageManager storageManager; - private BallotQuestion[] questionsForChoosingChannel; - private BallotQuestion[] questions; + private List questionsForChoosingChannel; + private List questions; private QuestionSelector questionSelector; private LinkedBlockingQueue queue; @@ -33,38 +33,18 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { private Logger logger; private ControllerState state; - private boolean shutDownHasBeenCalled; + private volatile boolean shutDownHasBeenCalled; protected final int MAX_REQUEST_IDENTIFIER = 100000; private static int requestCounter = 0; - private UIElement waitForCommitMessage; - private UIElement waitForAuditMessage; - private UIElement waitForCastMessage; - - public VotingBoothImpl () { logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); shutDownHasBeenCalled = false; queue = new LinkedBlockingQueue<>(); - - waitForCommitMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) - .build(); - waitForAuditMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) - .build(); - waitForCastMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) - .build(); - - state = new VotingBoothImpl.ControllerState(); - + state = new ControllerState(); } @Override @@ -80,42 +60,22 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } @Override - public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) { + public void setBallotChannelChoiceQuestions(List questions) { logger.info("setting questions"); this.questionsForChoosingChannel = questions; } - @Override - public void setBallotChannelChoiceQuestions(ArrayList questions) { - BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; - for (int i = 0; i < bqArr.length; ++i) { - bqArr[i] = questions.get(i); - } - setBallotChannelChoiceQuestions(bqArr); - } - @Override public void setChannelQuestionSelector(QuestionSelector selector) { this.questionSelector = selector; } @Override - public void setBallotRaceQuestions(BallotQuestion[] questions) { + public void setBallotRaceQuestions(List questions) { logger.info("setting questions"); this.questions = questions; } - @Override - public void setBallotRaceQuestions(ArrayList questions) { - // TODO: why does the toArray method not work?? - //BallotQuestion[] bqArr = (BallotQuestion[])(questions.toArray()); - BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; - for (int i = 0; i < bqArr.length; ++i) { - bqArr[i] = questions.get(i); - } - setBallotRaceQuestions(bqArr); - } - @Override public void run() { logger.info("run command has been called"); @@ -124,17 +84,6 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } - @Override - public void shutDown() { - logger.info("shutDown command has been called"); - synchronized (this) { - shutDownHasBeenCalled = true; - } - - } - - - private void runVotingFlow () { logger.info("entered the voting flow"); @@ -151,64 +100,70 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } } - private void doShutDown () { - logger.info("running shutDown"); + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + queue.add(new ShutDownCommand()); } private void handleSingleTask (ControllerCommand task) { - if (task instanceof RestartVotingCommand) { - doRestartVoting (); - return; - } - if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) { + if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) { + // probably an old command relating to some old ballot serial number. Simply log it and ignore it. String errorMessage = "handleSingleTask: received a task too old. " + task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; - logger.warn (errorMessage); + logger.debug(errorMessage); return; } - if (task instanceof CastCommand) { - doCast(); - return; + if (task instanceof RestartVotingCommand) { + doRestartVoting (); + } + else if (task instanceof CastCommand) { + doFinalize(false); } else if (task instanceof AuditCommand) { - doAudit(); - return; + doFinalize(true); } else if (task instanceof ChannelChoiceCommand) { doChooseChannel(); - return; } else if (task instanceof ChannelDeterminedCommand) { doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); - return; } else if (task instanceof EncryptAndCommitBallotCommand) { doCommit ((EncryptAndCommitBallotCommand)task); - return; + } + else if (task instanceof ReportErrorCommand) { + doReportErrorAndForceRestart((ReportErrorCommand)task); + } + else if (task instanceof ShutDownCommand) { + // wasShutDownCalled is now true. Do nothing. + // The program will not access the command queue anymore, and will exit normally + if (!wasShutDownCalled()) { + logger.warn("Received a ShutDownCommand command. At this point shutDownHasBeenCalled flag should have been True, but it's not..."); + shutDownHasBeenCalled = true; + } } else { - String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " + - task.getClass().getName(); - logger.error(errorMessage); - throw new RuntimeException(errorMessage); + logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); + doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); } } - /* - Map taskHandlers = new Map<>() { -CaskTask.getClass().getName() : doCast(), -ChannelChoiceCommand.getClass().getName() : doChooseChannel(), -} - - - - */ - - private synchronized boolean wasShutDownCalled () { + private boolean wasShutDownCalled () { return shutDownHasBeenCalled; } + private void doShutDown () { + logger.info("running callShutDown"); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.SHUT_DOWN; + //TODO: add commands to actually shut down the machine + } + private void doRestartVoting () { queue.clear(); state.clearPlaintext(); @@ -216,7 +171,22 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), state.stateIdentifier = VBState.NEW_VOTER; state.currentBallotSerialNumber += 1; - ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber , this.queue)); + ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + + private void doReportErrorAndForceRestart(ReportErrorCommand task) { + doReportErrorAndForceRestart(task.getErrorMessage()); + } + + private void doReportErrorAndForceRestart(UIElement errorMessage) { + queue.clear(); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.FATAL_ERROR_FORCE_NEW_VOTER; + state.currentBallotSerialNumber += 1; + ui.showErrorMessageWithButtons(errorMessage, + new UIElement[]{SystemMessages.getRestartVotingButton()}, + new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } private void doChooseChannel () { @@ -227,7 +197,7 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doChooseChannel: current state is " + state.stateIdentifier); + logger.debug("doChooseChannel: current state is " + state.stateIdentifier); // ignore this request } } @@ -236,15 +206,14 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { logger.debug("doing set channel and ask questions"); state.stateIdentifier = VBState.ANSWER_QUESTIONS; - BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers; + List channelChoiceAnswers = task.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); - state.stateIdentifier = VBState.ANSWER_QUESTIONS; ui.askVoterQuestions(state.channelSpecificQuestions, new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); + logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); // ignore this request } } @@ -254,10 +223,8 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; - VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); - state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); - state.secrets = encryptionAndSecrets.getSecrets(); - ui.notifyVoterToWaitForFinish(waitForCommitMessage, + setBallotData (task); + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); @@ -266,38 +233,38 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doCommit: current state is " + state.stateIdentifier); + logger.debug("doCommit: current state is " + state.stateIdentifier); // ignore this request } } - - private void doAudit () { - if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { - logger.debug("doing audit"); - state.stateIdentifier = VBState.FINALIZING; - outputDevice.audit(state.secrets, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - ui.notifyVoterToWaitForFinish(waitForAuditMessage, - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - } - else { - logger.warn("doAudit: current state is " + state.stateIdentifier); - // ignore this request - } + private void setBallotData (EncryptAndCommitBallotCommand task) { + state.plaintextBallot = PlaintextBallot.newBuilder() + .setSerialNumber(task.getBallotSerialNumber()) + .addAllAnswers(task.getVotingAnswers()) + .build(); + VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); + state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + state.secrets = encryptionAndSecrets.getSecrets(); } - private void doCast () { + private void doFinalize (boolean auditRequested) { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { - logger.debug("casting ballot"); + logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; - outputDevice.castBallot( - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - ui.notifyVoterToWaitForFinish(waitForCastMessage, + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + if (auditRequested) { + outputDevice.audit(state.secrets, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + outputDevice.castBallot( + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } } else { - logger.warn("doCast: current state is " + state.stateIdentifier); + logger.debug("doFinalize: current state is " + state.stateIdentifier); // ignore this request } } @@ -312,14 +279,16 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), ANSWER_QUESTIONS, COMMITTING_TO_BALLOT, CAST_OR_AUDIT, - FINALIZING + FINALIZING, + FATAL_ERROR_FORCE_NEW_VOTER, + SHUT_DOWN } private class ControllerState { - public VotingBoothImpl.VBState stateIdentifier; + public VBState stateIdentifier; public int channelIdentifier; - public BallotQuestion[] channelSpecificQuestions; + public List channelSpecificQuestions; public PlaintextBallot plaintextBallot; public EncryptedBallot encryptedBallot; public BallotSecrets secrets; @@ -338,12 +307,10 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), public void clearPlaintext () { - //TODO: Do we need safe erasure? plaintextBallot = null; } public void clearCiphertext () { - //TODO: Do we need safe erasure? encryptedBallot = null; secrets = null; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 0a5522f..69d5123 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; - +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.RestartVotingCommand; @@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class CastOrAuditCallback extends ControllerCallback { +public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); public CastOrAuditCallback(int requestId, @@ -20,18 +20,18 @@ public class CastOrAuditCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert (result instanceof FinalizeBallotChoice); - + public void onSuccess(FinalizeBallotChoice result) { if (result == FinalizeBallotChoice.CAST) { - controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); } else if (result == FinalizeBallotChoice.AUDIT) { - controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); } else { logger.error("CastOrAuditCallback got an unrecognized response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnrecognizedFinalizeResponseMessage())); } } @@ -39,7 +39,9 @@ public class CastOrAuditCallback extends ControllerCallback { @Override public void onFailure(Throwable t) { logger.error("CastOrAuditCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnrecognizedFinalizeResponseMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index c6db8d4..f6abd5c 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -1,18 +1,18 @@ package meerkat.voting.controller.callbacks; -import meerkat.protobuf.Voting; -import meerkat.voting.controller.commands.ChannelDeterminedCommand; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.SystemMessages; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; /** * Created by hai on 11/04/16. */ -public class ChannelChoiceCallback extends ControllerCallback { +public class ChannelChoiceCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); public ChannelChoiceCallback(int requestId, @@ -22,22 +22,22 @@ public class ChannelChoiceCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert (result instanceof Voting.BallotAnswer[]); - if (((Voting.BallotAnswer[])result).length != 0) { + public void onSuccess(List result) { + if (result.size() != 0) { logger.debug("callback for channel choice returned success"); - controllerQueue.add( - new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } else { logger.debug("ChannelChoiceCallback got a cancellation response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } @Override public void onFailure(Throwable t) { logger.error("channel choice initiated a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulChannelChoiceMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java index 2c33cbc..d5684d2 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -1,14 +1,18 @@ package meerkat.voting.controller.callbacks; +/** + * Created by hai on 18/05/16. + */ import com.google.common.util.concurrent.FutureCallback; import meerkat.voting.controller.commands.ControllerCommand; import java.util.concurrent.LinkedBlockingQueue; -public abstract class ControllerCallback implements FutureCallback { +public abstract class ControllerCallback implements FutureCallback { + private final int requestIdentifier; private final long ballotSerialNumber; - protected LinkedBlockingQueue controllerQueue; + private LinkedBlockingQueue controllerQueue; protected ControllerCallback (int requestId, long ballotSerialNumber, @@ -21,7 +25,13 @@ public abstract class ControllerCallback implements FutureCallback { protected int getRequestIdentifier () { return requestIdentifier; } + protected long getBallotSerialNumber () { return ballotSerialNumber; } + + protected void enqueueCommand (ControllerCommand command) { + controllerQueue.add(command); + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java new file mode 100644 index 0000000..34f1194 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class ErrorMessageRestartCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(ErrorMessageRestartCallback.class); + + public ErrorMessageRestartCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Integer result) { + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("Error message execution initiated a failure: " + t); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java deleted file mode 100644 index c251a0f..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java +++ /dev/null @@ -1,32 +0,0 @@ -package meerkat.voting.controller.callbacks; - -import meerkat.voting.controller.commands.ControllerCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Created by hai on 21/04/16. - */ -public class HaltCallback extends ControllerCallback{ - protected final static Logger logger = LoggerFactory.getLogger(HaltCallback.class); - - public HaltCallback(int requestId, - long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { - super(requestId, ballotSerialNumber, controllerQueue); - } - - - @Override - public void onSuccess(Object result) { - throw new UnsupportedOperationException("HaltCallback: onSuccess: There cannot be a successful return for this task. Returned value is " + result); - } - - @Override - public void onFailure(Throwable t) { - logger.error("Halting initiated a failure: " + t); - } - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java index bdb53c3..9b4e365 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class NewVoterCallback extends ControllerCallback { +public class NewVoterCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); public NewVoterCallback(int requestId, @@ -18,15 +18,14 @@ public class NewVoterCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { + public void onSuccess(Void v) { logger.debug("callback for new voting returned success"); - assert v==null; - controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); } @Override public void onFailure(Throwable t) { logger.error("New voting session got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java index 81a14c4..2432f49 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java @@ -1,13 +1,15 @@ package meerkat.voting.controller.callbacks; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class OutputDeviceCallback extends ControllerCallback { +public class OutputDeviceCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); public OutputDeviceCallback(int requestId, @@ -17,13 +19,14 @@ public class OutputDeviceCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { - assert v instanceof Void; + public void onSuccess(Void v) { } @Override public void onFailure(Throwable t) { logger.error("WaitForFinishCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getOutputDeviceFailureMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 5e0cc1a..5317374 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,15 +1,18 @@ package meerkat.voting.controller.callbacks; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; -public class VotingCallback extends ControllerCallback { +public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); public VotingCallback(int requestId, @@ -19,22 +22,22 @@ public class VotingCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert result instanceof Voting.BallotAnswer[]; - if (((Voting.BallotAnswer[])result).length != 0) { + public void onSuccess(List result) { + if (result.size() != 0) { logger.debug("callback for voting returned success"); - controllerQueue.add( - new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } else { logger.debug("VotingCallback got a cancellation response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } @Override public void onFailure(Throwable t) { logger.error("voting initiated a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulVotingMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index d56327d..9f7a159 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,13 +1,15 @@ package meerkat.voting.controller.callbacks; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class WaitForFinishCallback extends ControllerCallback { +public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); public WaitForFinishCallback(int requestId, @@ -17,13 +19,14 @@ public class WaitForFinishCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { - assert v instanceof Void; + public void onSuccess(Void v) { } @Override public void onFailure(Throwable t) { logger.error("WaitForFinishCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getSomethingWrongMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java index 8fefbe7..47d6f8b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -1,14 +1,15 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; +import java.util.List; /** * Created by hai on 11/04/16. */ public class ChannelDeterminedCommand extends ControllerCommand { - public Voting.BallotAnswer[] channelChoiceAnswers; + public List channelChoiceAnswers; - public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, List answers) { super(requestIdentifier, ballotSerialNumber); channelChoiceAnswers = answers; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index bad2ff7..074216f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -1,12 +1,18 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; + +import java.util.List; public class EncryptAndCommitBallotCommand extends ControllerCommand { - public Voting.BallotAnswer[] votingAnswers; + private final List votingAnswers; - public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, List answers) { super(requestIdentifier, ballotSerialNumber); votingAnswers = answers; } + + public List getVotingAnswers() { + return votingAnswers; + } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java new file mode 100644 index 0000000..b4a1fe7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting.*; + +public class ReportErrorCommand extends ControllerCommand { + private final UIElement errorMessage; + + public ReportErrorCommand(int requestIdentifier, long ballotSerialNumber, UIElement errorMessage) { + super(requestIdentifier, ballotSerialNumber); + this.errorMessage = errorMessage; + } + + public UIElement getErrorMessage() { + return errorMessage; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java new file mode 100644 index 0000000..ee3c0f2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ShutDownCommand extends ControllerCommand { + public ShutDownCommand() { + super(0, 0); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index 3fd2188..e409e36 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -1,20 +1,18 @@ package meerkat.voting.controller.selector; import meerkat.protobuf.Voting.*; +import java.util.List; /** * Created by hai on 02/05/16. */ -public abstract class QuestionSelector { +public interface QuestionSelector { - protected Object selectionData; - protected BallotQuestion[] allBallotQuestions; + public void setAllBallotQuestions (List allBallotQuestions); - public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { - this.selectionData = selectionData; - this.allBallotQuestions = allBallotQuestions; - } + public void setSelectionData(SelectionData data); - public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers); - public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers); + public int getChannelIdentifier (List channelChoiceAnswers); + + public List selectQuestionsForVoter (List channelChoiceAnswers); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java new file mode 100644 index 0000000..24a1125 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java @@ -0,0 +1,7 @@ +package meerkat.voting.controller.selector; + +/** + * Created by hai on 11/05/16. + */ +public class SelectionData { +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java index 83ae516..544a86d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java @@ -1,39 +1,60 @@ package meerkat.voting.controller.selector; -import java.util.HashMap; -import java.lang.Math; - /** - * Created by hai on 02/05/16. + * This class is the SelectionData used to initialize a SimpleListCategoriesSelector. + * It holds a table of question categories. + * Every answer in the channel choice phase dictates a category of questions to include in the ballot. + * This class is simply only the data class of these categories. + * Specifically the questionSelectionsByAnswer member is this categories table: + * questionSelectionsByAnswer[questionNumber][answerNumber] is an array of question indices to include in ballot + * whenever the voter answered answerNumber on question questionNumber in the channel choice phase. + * Also the sharedDefaults member is a category of question indices to include for EVERY voter, + * regardless of his channel choice answers */ -public class SimpleCategoriesData { +public class SimpleCategoriesData extends SelectionData{ - private int[] sharedDefaults; - private HashMap questionsSelections; + private int[] sharedDefaults; // a category of questions to include for every voter + // the categories + // first index is the question number, the second is the answer number. the value is an array of question indices in this category + private int[][][] questionSelectionsByAnswer; private int maxQuestionNumber; public SimpleCategoriesData() { sharedDefaults = new int[0]; - questionsSelections = new HashMap(); + questionSelectionsByAnswer = new int[0][][]; maxQuestionNumber = -1; } public void setSharedDefaults(int[] sharedDefaultsIndices) { - this.sharedDefaults = sharedDefaultsIndices; - maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices)); + this.sharedDefaults = sharedDefaultsIndices.clone(); + maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices)); } public int[] getSharedDefaults() { return sharedDefaults; } - public void setItem(SingleChosenAnswer key, int[] questionIndices) { - questionsSelections.put(key, questionIndices); - maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices)); + public void setItem(int questionNumber, int answerNumber, int[] questionIndices) { + if (questionNumber >= questionSelectionsByAnswer.length) { + int[][][] tmp = new int[questionNumber+1][][]; + System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length); + tmp[questionNumber] = new int[0][]; + questionSelectionsByAnswer = tmp; + } + + if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) { + int[][] tmp = new int[answerNumber+1][]; + System.arraycopy(questionSelectionsByAnswer[questionNumber], 0, + tmp, 0, questionSelectionsByAnswer[questionNumber].length); + questionSelectionsByAnswer[questionNumber] = tmp; + } + + questionSelectionsByAnswer[questionNumber][answerNumber] = questionIndices.clone(); + maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(questionIndices)); } - public int[] getItem(SingleChosenAnswer key) { - return questionsSelections.get(key); + public int[] getItem(int questionNumber, int answerNumber) { + return questionSelectionsByAnswer[questionNumber][answerNumber]; } public int getMaxQuestionNumber() { @@ -41,7 +62,7 @@ public class SimpleCategoriesData { } - private static int maxInt(int[] arr) { + private static int maxIntInArray(int[] arr) { int m = -1; for (int i: arr) { m = Math.max(i , m); @@ -53,8 +74,11 @@ public class SimpleCategoriesData { String s = "SimpleCategoriesData:\n"; s += "shared : " + arrayToString(sharedDefaults) + "\n"; s += "map : \n"; - for (SingleChosenAnswer key : questionsSelections.keySet()) { - s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n"; + for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) { + for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) { + s += "(" + questionNumber + ", " + answerNumber + ") -> " + + arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n"; + } } return s; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 31911e6..d953246 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -1,75 +1,88 @@ package meerkat.voting.controller.selector; -import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; -import meerkat.protobuf.Voting.*; +import meerkat.protobuf.Voting.BallotAnswer; +import meerkat.protobuf.Voting.BallotQuestion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; /** - * Created by hai on 02/05/16. + * A simple implementation of a QuestionSelector. + * This implementation simply regards every single answer in the channel choice phase as an identifier of a category + * Every category is an array of ballot questions. + * Data of categories is initialized and stored by a SimpleCategoriesData object. + * After receiving the answers from a channel choice phase, this class simply gathers all the categories + * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question + * is included if its index appears in any chosen category, or in the default category shared by all voters) */ -public class SimpleListCategoriesSelector extends QuestionSelector { +public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + private BallotQuestion[] allBallotQuestions; + private SimpleCategoriesData selectionData; private boolean[] isSelected; - public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { - super(selectionData, allBallotQuestions); - initializeAttributes (allBallotQuestions); - } - public SimpleListCategoriesSelector(Object selectionData, ArrayList allBallotQuestions) { - super(selectionData, null); - BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()]; - for (int i = 0; i < questionsArr.length; ++i) { - questionsArr[i] = allBallotQuestions.get(i); - } - initializeAttributes (questionsArr); + public SimpleListCategoriesSelector() { + this.allBallotQuestions = null; + this.selectionData = null; } - private void initializeAttributes (BallotQuestion[] allBallotQuestions) { - assert selectionData instanceof SimpleCategoriesData; - this.allBallotQuestions = allBallotQuestions; - SimpleCategoriesData data = (SimpleCategoriesData) selectionData; - int maxQuestionNumber = data.getMaxQuestionNumber(); - int length = allBallotQuestions.length; - if (maxQuestionNumber >= length) { - String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + length + " questions totally"; - logger.error(errorMessage); - throw new ValueException(errorMessage); - } - isSelected = new boolean[allBallotQuestions.length]; - } - - @Override - public int getChannelIdentifier(BallotAnswer[] channelChoiceAnswers) { + public void setAllBallotQuestions(List allBallotQuestions) { + this.allBallotQuestions = (BallotQuestion[])allBallotQuestions.toArray(); + isSelected = new boolean[this.allBallotQuestions.length]; + assertDataValid(); + } + + @Override + public void setSelectionData(SelectionData data) { + if (! (data instanceof SimpleCategoriesData)) { + String errorMessage = "Initialization of SimpleListCategoriesSelector with wrong object type"; + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + this.selectionData = (SimpleCategoriesData)data; + assertDataValid(); + } + + private void assertDataValid () { + if (selectionData != null && allBallotQuestions != null) { + int questionsLength = allBallotQuestions.length; + int maxQuestionNumber = selectionData.getMaxQuestionNumber(); + if (maxQuestionNumber >= questionsLength) { + String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + questionsLength + " questions totally"; + logger.error(errorMessage); + throw new IndexOutOfBoundsException(errorMessage); + } + } + } + + @Override + public int getChannelIdentifier(List channelChoiceAnswers) { return 0; } @Override - public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + public List selectQuestionsForVoter(List channelChoiceAnswers) { java.util.Arrays.fill(isSelected, false); - markSelected(data.getSharedDefaults()); - markSelectionsOfVoterChannelChoice (channelChoiceAnswers); + markSelected(selectionData.getSharedDefaults()); + markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray()); int[] questionIndices = extractSelectedIndices(); - BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length]; - for (int i = 0; i < questionIndices.length; ++i) { - selectedQuestions[i] = allBallotQuestions[questionIndices[i]]; + List selectedQuestions = new ArrayList<>(); + for (int questionIndex: questionIndices) { + selectedQuestions.add(allBallotQuestions[questionIndex]); } return selectedQuestions; } private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; for (int q = 0; q < channelChoiceAnswers.length; ++q) { BallotAnswer ballotAnswer = channelChoiceAnswers[q]; assertAnswerLengthIsOne(ballotAnswer, q); - SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0)); - assertKeyInSelectionData(key); - markSelected(data.getItem(key)); + assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0)); + markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0))); } } @@ -81,17 +94,16 @@ public class SimpleListCategoriesSelector extends QuestionSelector { errorMessage += " " + i; } logger.error(errorMessage); - throw new ValueException(errorMessage); + throw new IllegalArgumentException(errorMessage); } } - private void assertKeyInSelectionData(SingleChosenAnswer key) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; - int[] questionListToAdd = data.getItem(key); + private void assertKeyInSelectionData(int questionNumber, int answerNumber) { + int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber); if (null == questionListToAdd) { - String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + key.answerNumber + " for question number " + key.questionNumber; + String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + answerNumber + " for question number " + questionNumber; logger.error(errorMessage); - throw new ValueException(errorMessage); + throw new IllegalArgumentException(errorMessage); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java deleted file mode 100644 index fad377b..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java +++ /dev/null @@ -1,31 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * Created by hai on 02/05/16. - */ -public class SingleChosenAnswer { - public int questionNumber; - public long answerNumber; - - public SingleChosenAnswer(int questionNumber, long answerNumber) { - this.questionNumber = questionNumber; - this.answerNumber = answerNumber; - } - - public String toString() { - return "SingleChosenAnswer(" + questionNumber + ", " + answerNumber + ")"; - } - - public boolean equals (Object other) { - if (!(other instanceof SingleChosenAnswer)) { - return false; - } - SingleChosenAnswer o = (SingleChosenAnswer)other; - return (o.questionNumber == this.questionNumber) && (o.answerNumber == this.answerNumber); - } - - @Override - public int hashCode () { - return questionNumber*1000 + (int)answerNumber; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 4b6486e..1ab1574 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -7,9 +7,7 @@ import meerkat.protobuf.Voting.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.Date; -import java.util.StringTokenizer; -import java.util.Timer; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import meerkat.voting.controller.callbacks.*; @@ -45,54 +43,47 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { logger.info("entered the voting flow"); while (true) { try { - UICommand task = queue.take(); - handleSingleTask (task); + UICommand command = queue.take(); + handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from task queue " + e); + logger.warn ("Interrupted while reading from command queue " + e); } } } - private void handleSingleTask (UICommand task) { - if (!(task instanceof TickCommand)) { + private void handleSingleCommand(UICommand command) { + if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { stopWaiting(); } } - if (task instanceof StartSessionUICommand) { - doShowWelcomeScreen((StartSessionUICommand)task); - return; + if (command instanceof StartSessionUICommand) { + doShowWelcomeScreen((StartSessionUICommand)command); } - else if (task instanceof ChannelChoiceUICommand) { - doAskChannelChoiceQuestions((ChannelChoiceUICommand)task); - return; + else if (command instanceof ChannelChoiceUICommand) { + doAskChannelChoiceQuestions((ChannelChoiceUICommand)command); } - else if (task instanceof RaceVotingUICommand) { - doAskVotingQuestions((RaceVotingUICommand)task); - return; + else if (command instanceof RaceVotingUICommand) { + doAskVotingQuestions((RaceVotingUICommand)command); } - else if (task instanceof CastOrAuditUICommand) { - doCastOrAudit ((CastOrAuditUICommand)task); - return; + else if (command instanceof CastOrAuditUICommand) { + doCastOrAudit ((CastOrAuditUICommand)command); } - else if (task instanceof HaltCommand) { - doHalt((HaltCommand)task); - return; + else if (command instanceof FatalErrorUICommand) { + doFatalError((FatalErrorUICommand)command); } - else if (task instanceof WaitForFinishCommand) { - doWaitForFinish((WaitForFinishCommand)task); - return; + else if (command instanceof WaitForFinishUICommand) { + doWaitForFinish((WaitForFinishUICommand)command); } - else if (task instanceof TickCommand) { + else if (command instanceof TickCommand) { doTick (); - return; } else { - String errorMessage = "handleSingleTask: unknown type of UICommand received: " + - task.getClass().getName(); + String errorMessage = "handleSingleCommand: unknown type of UICommand received: " + + command.getClass().getName(); logger.error(errorMessage); throw new RuntimeException(errorMessage); } @@ -105,13 +96,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new StartSessionUICommand((ControllerCallback)callback)); } - private void doShowWelcomeScreen(StartSessionUICommand task) { + private void doShowWelcomeScreen(StartSessionUICommand command) { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); waitForEnter(null); - ControllerCallback callback = task.getCallback(); + ControllerCallback callback = command.getCallback(); assert (callback instanceof NewVoterCallback); - ((NewVoterCallback)callback).onSuccess(null); + callback.onSuccess(null); } private void stopWaiting () { @@ -138,45 +129,45 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } @Override - public void chooseChannel(BallotQuestion[] questions, FutureCallback callback) { + public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); - queue.add(task); + ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + queue.add(command); } - private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) { + private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) { logger.debug("UI: doAskChannelChoiceQuestions"); System.out.println("Showing questions for choosing channel:\n"); try { - BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); - task.getCallback().onSuccess(answers); + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); } catch (IOException e) { String errorMessage = "Channel choice failed due to IOException: " + e; logger.error (errorMessage); System.err.println(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @Override - public void askVoterQuestions(BallotQuestion[] questions, FutureCallback callback) { + public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); } - private void doAskVotingQuestions (RaceVotingUICommand task) { + private void doAskVotingQuestions (RaceVotingUICommand command) { logger.debug("UI: doAskVotingQuestions"); System.out.println("Showing questions for race voting:\n"); try { - BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); - task.getCallback().onSuccess(answers); + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); } catch (IOException e) { String errorMessage = "Asking voting questions failed due to IOException: " + e; logger.error (errorMessage); System.err.println(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @@ -186,7 +177,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); } - private void doCastOrAudit(CastOrAuditUICommand task) { + private void doCastOrAudit(CastOrAuditUICommand command) { logger.debug("UI entered doCastOrAudit"); System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); @@ -203,30 +194,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { else { throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'"); } - ControllerCallback callback = task.getCallback(); + ControllerCallback callback = command.getCallback(); assert (callback instanceof CastOrAuditCallback); ((CastOrAuditCallback)callback).onSuccess(fChoice); } catch (IllegalArgumentException|IOException e) { String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e; logger.error(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @Override - public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { + public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishCommand(message, (ControllerCallback)callback)); + queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); } - public void doWaitForFinish (WaitForFinishCommand task) { + public void doWaitForFinish (WaitForFinishUICommand command) { logger.debug("UI entered doWaitForFinish"); startWaitingTime = new Date(); - UIElement message = task.getMessage(); + UIElement message = command.getMessage(); String messageString; if (message.getType() != UIElementDataType.TEXT) { messageString = "Default message: encountered an error. System halting"; @@ -240,39 +231,57 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageAndHalt"); - queue.add(new HaltCommand(errorMessage, (ControllerCallback)callback)); + throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it."); } - private void doHalt (HaltCommand task) { - logger.debug("UI entered doHalt"); - UIElement errorMessage = task.getErrorMessage(); + @Override + public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageWithButtons"); + queue.clear(); + queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + } + + private void doFatalError (FatalErrorUICommand command) { + logger.debug("UI entered doFatalError"); + + UIElement errorMessage = command.getErrorMessage(); String errorMessageString; if (errorMessage.getType() != UIElementDataType.TEXT) { errorMessageString = "Default message: encountered an error. System halting"; } else { errorMessageString = bytesToString(errorMessage.getData()); } - System.out.println(errorMessageString); - while (true) { - try { - wait(); - } catch (InterruptedException e) { - logger.error("UI halt has been interrupted. Details: " + e); - ControllerCallback callback = task.getCallback(); - assert callback instanceof HaltCallback; - ((HaltCallback) callback).onFailure(e); + UIElement[] buttonLabels = command.getButtonLabels(); + String[] buttonLabelStrings = new String[buttonLabels.length]; + for (int i = 0; i < buttonLabels.length; ++i) { + if (buttonLabels[i].getType() != UIElementDataType.TEXT) { + buttonLabelStrings[i] = ""; + } else { + buttonLabelStrings[i] = bytesToString(errorMessage.getData()); } } + + System.out.println(errorMessageString); + for (int i = 0; i < buttonLabelStrings.length; ++i) { + System.out.println("" + i + " - " + buttonLabelStrings[i]); + } + + try { + String s = readInputLine(); + Integer chosenButton = new Integer(s); + command.getCallback().onSuccess(chosenButton); + } + catch (IOException e) { + String err = "doFatalError: some error with reading input from console. details: " + e; + logger.error(err); + command.getCallback().onFailure(e); + } + } - @Override - public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { - throw new UnsupportedOperationException(); - } - private void doTick () { if (startWaitingTime != null) { System.out.print ("."); // still waiting @@ -295,9 +304,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } - private void assertQuestionsAreValid (BallotQuestion[] questions) { - for (int index = 0; index < questions.length; ++index) { - BallotQuestion question = questions[index]; + private void assertQuestionsAreValid (List questions) { + for (int index = 0; index < questions.size(); ++index) { + BallotQuestion question = questions.get(index); if (question.getIsMandatory()) { String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory"; logger.error(errorMessage); @@ -311,14 +320,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private BallotAnswer[] askVoterForAnswers(BallotQuestion[] questions) throws IOException { + private List askVoterForAnswers(List questions) throws IOException { assertQuestionsAreValid (questions); - BallotAnswer answers[] = new BallotAnswer[questions.length]; + List answers = new ArrayList<>(); int index = 0; - while (index < questions.length) { - BallotQuestion question = questions[index]; + while (index < questions.size()) { + BallotQuestion question = questions.get(index); System.out.println("Question number " + index); showQuestionOnScreen(question); @@ -330,13 +339,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } else if (s.equals("back") || s.equals("b")) { --index; + answers.remove(index); } else if (s.equals("skip") || s.equals("s")) { - answers[index] = translateStringAnswerToProtoBufMessageAnswer(""); + answers.add(translateStringAnswerToProtoBufMessageAnswer("")); ++index; } else { - answers[index] = translateStringAnswerToProtoBufMessageAnswer(s); + answers.add(translateStringAnswerToProtoBufMessageAnswer(s)); ++index; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index ae96f7b..192dd1c 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -3,6 +3,8 @@ package meerkat.voting.ui; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; +import java.util.List; + /** * An interface for the user interface component of the voting booth @@ -25,14 +27,14 @@ public interface VotingBoothUI { * @param questions questions to determine the right voting channel for this voter * @param callback that's where we store the answers to decide channel upon for the current voter */ - public void chooseChannel (BallotQuestion[] questions, FutureCallback callback); + public void chooseChannel (List questions, FutureCallback> callback); /** * Presents the set of questions to the voter. Collect all his responses. * @param questions all ballot questions to present to the voter * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session */ - public void askVoterQuestions (BallotQuestion[] questions, FutureCallback callback); + public void askVoterQuestions (List questions, FutureCallback> callback); /** * Get a response from the voter on how to finalize the ballot. @@ -51,7 +53,7 @@ public interface VotingBoothUI { * @param message a message to show the user on the UI device while waiting * @param callback a success return value of the wait (cancelling returns false) */ - public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); + public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); /** * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 993f64b..1b2f72f 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 21/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index 22d2ff3..5ad4391 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -1,22 +1,24 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; + +import java.util.List; /** * Created by hai on 18/04/16. */ public class ChannelChoiceUICommand extends UICommand { - private final BallotQuestion[] questions; + private final List questions; - public ChannelChoiceUICommand(BallotQuestion[] questions, ControllerCallback callback) + public ChannelChoiceUICommand(List questions, ControllerCallback callback) { super(callback); this.questions = questions; } - public BallotQuestion[] getQuestions () { + public List getQuestions () { return this.questions; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java new file mode 100644 index 0000000..7679130 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -0,0 +1,28 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.UIElement; +import meerkat.voting.controller.callbacks.*; + +/** + * Created by hai on 18/04/16. + */ +public class FatalErrorUICommand extends UICommand { + + private final UIElement errorMessage; + private final UIElement[] buttonLabels; + + public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) + { + super(callback); + this.errorMessage = errorMessage; + this.buttonLabels = buttonLabels; + } + + public UIElement getErrorMessage() { + return this.errorMessage; + } + + public UIElement[] getButtonLabels() { + return this.getButtonLabels(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java deleted file mode 100644 index 5213354..0000000 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package meerkat.voting.ui.uicommands; - -import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; - -/** - * Created by hai on 18/04/16. - */ -public class HaltCommand extends UICommand { - - private final UIElement errorMessage; - - public HaltCommand(UIElement errorMessage, ControllerCallback callback) - { - super(callback); - this.errorMessage = errorMessage; - } - - public UIElement getErrorMessage () { - return this.errorMessage; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 31d2706..6430e59 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -1,22 +1,24 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; + +import java.util.List; /** * Created by hai on 18/04/16. */ public class RaceVotingUICommand extends UICommand { - private final BallotQuestion[] questions; + private final List questions; - public RaceVotingUICommand(BallotQuestion[] questions, ControllerCallback callback) + public RaceVotingUICommand(List questions, ControllerCallback callback) { super(callback); this.questions = questions; } - public BallotQuestion[] getQuestions () { + public List getQuestions () { return this.questions; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index f1bc146..393afa7 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 3192f4c..0872ea3 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index b22fdef..460b7d0 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; //TODO: make this class generic public abstract class UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java similarity index 60% rename from voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java rename to voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index fe9b1cc..5c48359 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -1,17 +1,17 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. */ -public class WaitForFinishCommand extends UICommand { +public class WaitForFinishUICommand extends UICommand { private final UIElement message; - public WaitForFinishCommand(UIElement message, ControllerCallback callback) + public WaitForFinishUICommand(UIElement message, ControllerCallback callback) { super(callback); this.message = message; From 76d3fdeac290254da0e8d249fb02acba1a7f28ff Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 7 Jun 2016 16:15:08 +0300 Subject: [PATCH 29/66] Fixed the Selector classes. Fixed the crypto classes to handle signatures as well. Some more other fixes --- .../src/main/proto/meerkat/voting.proto | 19 +++ .../controller/VotingBoothController.java | 7 +- .../voting/controller/VotingBoothImpl.java | 46 +++--- .../callbacks/ChannelChoiceCallback.java | 24 +-- .../callbacks/VoterCancelException.java | 8 + .../controller/callbacks/VotingCallback.java | 24 +-- .../controller/commands/ShutDownCommand.java | 10 -- .../controller/selector/QuestionSelector.java | 7 +- .../controller/selector/SelectionData.java | 7 - .../selector/SimpleCategoriesData.java | 97 ------------ .../SimpleListCategoriesSelector.java | 144 ++++++++---------- ...othEncryptor.java => VBCryptoManager.java} | 19 +-- .../voting/encryptor/VBCryptoManagerImpl.java | 67 ++++++++ .../voting/encryptor/VBEncryptorImpl.java | 14 -- .../voting/output/BallotOutputDevice.java | 2 +- .../output/SystemConsoleOutputDevice.java | 6 +- .../meerkat/voting/ui/SystemConsoleUI.java | 31 +++- .../java/meerkat/voting/ui/VotingBoothUI.java | 5 + 18 files changed, 259 insertions(+), 278 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java rename voting-booth/src/main/java/meerkat/voting/encryptor/{VotingBoothEncryptor.java => VBCryptoManager.java} (60%) create mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 8ece676..6c0b1e2 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -71,6 +71,12 @@ message EncryptedBallot { RerandomizableEncryptedMessage data = 2; } +message SignedEncryptedBallot { + EncryptedBallot encrypted_ballot = 1; + bytes signer_id = 2; + Signature signature = 3; +} + message BallotSecrets { PlaintextBallot plaintext_ballot = 1; @@ -126,3 +132,16 @@ message ElectionParams { // Data required in order to access the Bulletin Board Servers BulletinBoardClientParams bulletinBoardClientParams = 8; } + +message Category { + repeated uint32 questionIndex = 1; +} + +message CategoryChooser { + repeated Category category = 1; +} + +message SimpleCategoriesSelectionData { + Category shared_defaults = 1; + repeated CategoryChooser categoryChooser = 2; +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index 057f13d..6b706f3 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -2,12 +2,11 @@ package meerkat.voting.controller; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.ui.VotingBoothUI; -import meerkat.voting.encryptor.VotingBoothEncryptor; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; -import java.util.ArrayList; import java.util.List; @@ -19,12 +18,12 @@ public interface VotingBoothController extends Runnable{ /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection - * @param vbEncryptor the encryption module + * @param vbCrypto the crypto module * @param vbUI User interface in which the voter chooses his answers * @param vbStorageManager storage component for handling files and USB sticks */ public void init (BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, + VBCryptoManager vbCrypto, VotingBoothUI vbUI, StorageManager vbStorageManager); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index cd53f65..2d79d33 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,17 +1,19 @@ package meerkat.voting.controller; -import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.selector.QuestionSelector; -import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.encryptor.VBCryptoManager; +import meerkat.voting.encryptor.VBCryptoManager.EncryptionAndSecrets; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import meerkat.voting.ui.VotingBoothUI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.security.SignatureException; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; @@ -21,7 +23,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class VotingBoothImpl implements VotingBoothController { private BallotOutputDevice outputDevice; - private VotingBoothEncryptor encryptor; + private VBCryptoManager crypto; private VotingBoothUI ui; private StorageManager storageManager; private List questionsForChoosingChannel; @@ -49,12 +51,12 @@ public class VotingBoothImpl implements VotingBoothController { @Override public void init(BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, + VBCryptoManager vbCrypto, VotingBoothUI vbUI, StorageManager vbStorageManager) { logger.info("init is called"); this.outputDevice = outputDevice; - this.encryptor = vbEncryptor; + this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; } @@ -105,7 +107,7 @@ public class VotingBoothImpl implements VotingBoothController { logger.info("callShutDown command has been called"); shutDownHasBeenCalled = true; queue.clear(); - queue.add(new ShutDownCommand()); + ui.callShutDown(); } private void handleSingleTask (ControllerCommand task) { @@ -138,14 +140,6 @@ public class VotingBoothImpl implements VotingBoothController { else if (task instanceof ReportErrorCommand) { doReportErrorAndForceRestart((ReportErrorCommand)task); } - else if (task instanceof ShutDownCommand) { - // wasShutDownCalled is now true. Do nothing. - // The program will not access the command queue anymore, and will exit normally - if (!wasShutDownCalled()) { - logger.warn("Received a ShutDownCommand command. At this point shutDownHasBeenCalled flag should have been True, but it's not..."); - shutDownHasBeenCalled = true; - } - } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); @@ -208,7 +202,7 @@ public class VotingBoothImpl implements VotingBoothController { state.stateIdentifier = VBState.ANSWER_QUESTIONS; List channelChoiceAnswers = task.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); - state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); + state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } @@ -229,7 +223,7 @@ public class VotingBoothImpl implements VotingBoothController { state.currentBallotSerialNumber, this.queue)); outputDevice.commitToBallot(state.plaintextBallot, - state.encryptedBallot, + state.signedEncryptedBallot, new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { @@ -243,8 +237,14 @@ public class VotingBoothImpl implements VotingBoothController { .setSerialNumber(task.getBallotSerialNumber()) .addAllAnswers(task.getVotingAnswers()) .build(); - VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); - state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + EncryptionAndSecrets encryptionAndSecrets = null; + try { + encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); + } + catch (SignatureException | IOException e) { + // TODO: handle exception + } + state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } @@ -287,20 +287,20 @@ public class VotingBoothImpl implements VotingBoothController { private class ControllerState { public VBState stateIdentifier; - public int channelIdentifier; + public byte[] channelIdentifier; public List channelSpecificQuestions; public PlaintextBallot plaintextBallot; - public EncryptedBallot encryptedBallot; + public SignedEncryptedBallot signedEncryptedBallot; public BallotSecrets secrets; public int lastRequestIdentifier; public long currentBallotSerialNumber; public ControllerState () { plaintextBallot = null; - encryptedBallot = null; + signedEncryptedBallot = null; secrets = null; lastRequestIdentifier = -1; - channelIdentifier = -1; + channelIdentifier = null; channelSpecificQuestions = null; currentBallotSerialNumber = 0; } @@ -311,7 +311,7 @@ public class VotingBoothImpl implements VotingBoothController { } public void clearCiphertext () { - encryptedBallot = null; + signedEncryptedBallot = null; secrets = null; } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index f6abd5c..ea8094c 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -23,21 +23,21 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onSuccess(List result) { - if (result.size() != 0) { - logger.debug("callback for channel choice returned success"); - enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); - } - else { - logger.debug("ChannelChoiceCallback got a cancellation response: " + result); - enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); - } + logger.debug("callback for channel choice returned success"); + enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { - logger.error("channel choice initiated a failure: " + t); - enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), - getBallotSerialNumber(), - SystemMessages.getUnsuccessfulChannelChoiceMessage())); + if (t instanceof VoterCancelException) { + logger.debug("ChannelChoiceCallback got a cancellation response"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("channel choice initiated a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulChannelChoiceMessage())); + } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java new file mode 100644 index 0000000..4c0d411 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java @@ -0,0 +1,8 @@ +package meerkat.voting.controller.callbacks; + +/** + * Created by hai on 06/06/16. + */ +public class VoterCancelException extends Exception{ + // +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 5317374..4b6f2f7 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -23,21 +23,21 @@ public class VotingCallback extends ControllerCallback> { @Override public void onSuccess(List result) { - if (result.size() != 0) { - logger.debug("callback for voting returned success"); - enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); - } - else { - logger.debug("VotingCallback got a cancellation response: " + result); - enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); - } + logger.debug("callback for voting returned success"); + enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { - logger.error("voting initiated a failure: " + t); - enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), - getBallotSerialNumber(), - SystemMessages.getUnsuccessfulVotingMessage())); + if (t instanceof VoterCancelException) { + logger.debug("VotingCallback got a cancellation response"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("voting initiated a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulVotingMessage())); + } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java deleted file mode 100644 index ee3c0f2..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java +++ /dev/null @@ -1,10 +0,0 @@ -package meerkat.voting.controller.commands; - -/** - * Created by hai on 11/04/16. - */ -public class ShutDownCommand extends ControllerCommand { - public ShutDownCommand() { - super(0, 0); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index e409e36..e9decae 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -8,11 +8,8 @@ import java.util.List; */ public interface QuestionSelector { - public void setAllBallotQuestions (List allBallotQuestions); + public byte[] getChannelIdentifier (List channelChoiceAnswers); - public void setSelectionData(SelectionData data); + public List selectQuestionsForVoter (byte[] channelIdentifier); - public int getChannelIdentifier (List channelChoiceAnswers); - - public List selectQuestionsForVoter (List channelChoiceAnswers); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java deleted file mode 100644 index 24a1125..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * Created by hai on 11/05/16. - */ -public class SelectionData { -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java deleted file mode 100644 index 544a86d..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java +++ /dev/null @@ -1,97 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * This class is the SelectionData used to initialize a SimpleListCategoriesSelector. - * It holds a table of question categories. - * Every answer in the channel choice phase dictates a category of questions to include in the ballot. - * This class is simply only the data class of these categories. - * Specifically the questionSelectionsByAnswer member is this categories table: - * questionSelectionsByAnswer[questionNumber][answerNumber] is an array of question indices to include in ballot - * whenever the voter answered answerNumber on question questionNumber in the channel choice phase. - * Also the sharedDefaults member is a category of question indices to include for EVERY voter, - * regardless of his channel choice answers - */ -public class SimpleCategoriesData extends SelectionData{ - - private int[] sharedDefaults; // a category of questions to include for every voter - // the categories - // first index is the question number, the second is the answer number. the value is an array of question indices in this category - private int[][][] questionSelectionsByAnswer; - private int maxQuestionNumber; - - public SimpleCategoriesData() { - sharedDefaults = new int[0]; - questionSelectionsByAnswer = new int[0][][]; - maxQuestionNumber = -1; - } - - public void setSharedDefaults(int[] sharedDefaultsIndices) { - this.sharedDefaults = sharedDefaultsIndices.clone(); - maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices)); - } - - public int[] getSharedDefaults() { - return sharedDefaults; - } - - public void setItem(int questionNumber, int answerNumber, int[] questionIndices) { - if (questionNumber >= questionSelectionsByAnswer.length) { - int[][][] tmp = new int[questionNumber+1][][]; - System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length); - tmp[questionNumber] = new int[0][]; - questionSelectionsByAnswer = tmp; - } - - if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) { - int[][] tmp = new int[answerNumber+1][]; - System.arraycopy(questionSelectionsByAnswer[questionNumber], 0, - tmp, 0, questionSelectionsByAnswer[questionNumber].length); - questionSelectionsByAnswer[questionNumber] = tmp; - } - - questionSelectionsByAnswer[questionNumber][answerNumber] = questionIndices.clone(); - maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(questionIndices)); - } - - public int[] getItem(int questionNumber, int answerNumber) { - return questionSelectionsByAnswer[questionNumber][answerNumber]; - } - - public int getMaxQuestionNumber() { - return maxQuestionNumber; - } - - - private static int maxIntInArray(int[] arr) { - int m = -1; - for (int i: arr) { - m = Math.max(i , m); - } - return m; - } - - public String toString () { - String s = "SimpleCategoriesData:\n"; - s += "shared : " + arrayToString(sharedDefaults) + "\n"; - s += "map : \n"; - for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) { - for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) { - s += "(" + questionNumber + ", " + answerNumber + ") -> " + - arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n"; - } - } - return s; - } - - private String arrayToString (int[] a) { - if (a.length == 0) { - return "[]"; - } - String s = "[" + a[0]; - for (int i = 1; i < a.length; ++i) { - s += ", " + a[i]; - } - return s + "]"; - } - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index d953246..6181f05 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -1,89 +1,89 @@ package meerkat.voting.controller.selector; -import meerkat.protobuf.Voting.BallotAnswer; -import meerkat.protobuf.Voting.BallotQuestion; +import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; +import java.lang.Math; /** * A simple implementation of a QuestionSelector. * This implementation simply regards every single answer in the channel choice phase as an identifier of a category * Every category is an array of ballot questions. - * Data of categories is initialized and stored by a SimpleCategoriesData object. + * Data of categories is initialized and stored by a SimpleCategoriesSelectionData protobuf. * After receiving the answers from a channel choice phase, this class simply gathers all the categories * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question * is included if its index appears in any chosen category, or in the default category shared by all voters) */ public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); - private BallotQuestion[] allBallotQuestions; - private SimpleCategoriesData selectionData; - private boolean[] isSelected; + + private final BallotQuestion[] allBallotQuestions; + private final int[] sharedDefaults; + private final int[][][] categoryChoosers; + + private final static byte QUESTION_SELECTED = (byte)1; + private final static byte QUESTION_NOT_SELECTED = (byte)0; - public SimpleListCategoriesSelector() { - this.allBallotQuestions = null; - this.selectionData = null; - } - @Override - public void setAllBallotQuestions(List allBallotQuestions) { - this.allBallotQuestions = (BallotQuestion[])allBallotQuestions.toArray(); - isSelected = new boolean[this.allBallotQuestions.length]; - assertDataValid(); - } - - @Override - public void setSelectionData(SelectionData data) { - if (! (data instanceof SimpleCategoriesData)) { - String errorMessage = "Initialization of SimpleListCategoriesSelector with wrong object type"; - logger.error(errorMessage); - throw new RuntimeException(errorMessage); + public SimpleListCategoriesSelector(List allBallotQuestions, SimpleCategoriesSelectionData data) { + this.allBallotQuestions = new BallotQuestion[allBallotQuestions.size()]; + allBallotQuestions.toArray(this.allBallotQuestions); + sharedDefaults = listToIntArray(data.getSharedDefaults().getQuestionIndexList()); + int[][][] selectionDataTmp = new int[data.getCategoryChooserList().size()][][]; + int channelChoiceQuestionNumber = 0; + for (CategoryChooser catChooser: data.getCategoryChooserList()) { + selectionDataTmp[channelChoiceQuestionNumber] = new int[catChooser.getCategoryList().size()][]; + int channelChoiceAnswerNumber = 0; + for (Category category: catChooser.getCategoryList()) { + selectionDataTmp[channelChoiceQuestionNumber][channelChoiceAnswerNumber] = listToIntArray(category.getQuestionIndexList()); + ++channelChoiceAnswerNumber; + } + ++channelChoiceQuestionNumber; } - this.selectionData = (SimpleCategoriesData)data; + categoryChoosers = selectionDataTmp; assertDataValid(); } private void assertDataValid () { - if (selectionData != null && allBallotQuestions != null) { - int questionsLength = allBallotQuestions.length; - int maxQuestionNumber = selectionData.getMaxQuestionNumber(); - if (maxQuestionNumber >= questionsLength) { - String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + questionsLength + " questions totally"; - logger.error(errorMessage); - throw new IndexOutOfBoundsException(errorMessage); + int questionsLength = allBallotQuestions.length; + int maxQuestionIndex = -1; + for (int[][] categoryChooser: categoryChoosers) { + for (int[] category: categoryChooser) { + for (int index: category) { + maxQuestionIndex = Math.max(maxQuestionIndex, index); + } } } + if (maxQuestionIndex >= questionsLength) { + String errorMessage = "Selection data refers to question index " + maxQuestionIndex + " while we have only " + questionsLength + " questions totally"; + logger.error(errorMessage); + throw new IndexOutOfBoundsException(errorMessage); + } } + @Override - public int getChannelIdentifier(List channelChoiceAnswers) { - return 0; - } + public byte[] getChannelIdentifier(List channelChoiceAnswers) { + byte[] isSelected = new byte[allBallotQuestions.length]; + java.util.Arrays.fill(isSelected, QUESTION_NOT_SELECTED); - @Override - public List selectQuestionsForVoter(List channelChoiceAnswers) { - java.util.Arrays.fill(isSelected, false); - markSelected(selectionData.getSharedDefaults()); - markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray()); - int[] questionIndices = extractSelectedIndices(); - List selectedQuestions = new ArrayList<>(); - for (int questionIndex: questionIndices) { - selectedQuestions.add(allBallotQuestions[questionIndex]); + for (int i: sharedDefaults) { + isSelected[i] = QUESTION_SELECTED; } - return selectedQuestions; - } - private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { - for (int q = 0; q < channelChoiceAnswers.length; ++q) { - BallotAnswer ballotAnswer = channelChoiceAnswers[q]; - assertAnswerLengthIsOne(ballotAnswer, q); - assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0)); - markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0))); + int channelChoiceQuestionNumber = 0; + for (BallotAnswer ballotAnswer: channelChoiceAnswers) { + assertAnswerLengthIsOne(ballotAnswer, channelChoiceQuestionNumber); + for (int i: categoryChoosers[channelChoiceQuestionNumber][(int)ballotAnswer.getAnswer(0)]) { + isSelected[i] = QUESTION_SELECTED; + } } + + return isSelected; } private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { @@ -98,35 +98,23 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } } - private void assertKeyInSelectionData(int questionNumber, int answerNumber) { - int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber); - if (null == questionListToAdd) { - String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + answerNumber + " for question number " + questionNumber; - logger.error(errorMessage); - throw new IllegalArgumentException(errorMessage); - } - } - - private void markSelected (int[] questionIndices) { - for (int i: questionIndices) { - isSelected[i] = true; - } - } - - private int[] extractSelectedIndices() { - int nSelected = 0; - for (boolean b: isSelected) { - if (b) { - nSelected++; + @Override + public List selectQuestionsForVoter(byte[] channelIdentifier) { + List selectedQuestions = new ArrayList<>(); + for (int i = 0; i < channelIdentifier.length; ++i) { + if (channelIdentifier[i] == QUESTION_SELECTED) { + selectedQuestions.add(allBallotQuestions[i]); } } - int[] res = new int[nSelected]; - int currIndex = 0; - for (int questionNumber = 0; questionNumber < isSelected.length; ++questionNumber) { - if (isSelected[questionNumber]) { - res[currIndex] = questionNumber; - currIndex++; - } + return selectedQuestions; + } + + private int[] listToIntArray(List l) { + int[] res = new int[l.size()]; + int index = 0; + for (Integer i: l) { + res[index] = i; + ++index; } return res; } diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java similarity index 60% rename from voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java rename to voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index e9a885f..e664607 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -2,25 +2,27 @@ package meerkat.voting.encryptor; import meerkat.protobuf.Voting.*; +import java.io.IOException; +import java.security.SignatureException; + /** * An interface for the encryptor component of the voting booth */ -public interface VotingBoothEncryptor { - +public interface VBCryptoManager { /** * A simple class for pairing EncrypedBallot together with its matching BallotSecrets */ public class EncryptionAndSecrets { - private final EncryptedBallot encryptedBallot; + private final SignedEncryptedBallot signedEncryptedBallot; private final BallotSecrets secrets; - public EncryptionAndSecrets (EncryptedBallot encryptedBallot, BallotSecrets secrets) { - this.encryptedBallot = encryptedBallot; + public EncryptionAndSecrets (SignedEncryptedBallot encryptedBallot, BallotSecrets secrets) { + this.signedEncryptedBallot = encryptedBallot; this.secrets = secrets; } - public EncryptedBallot getEncryptedBallot () { - return encryptedBallot; + public SignedEncryptedBallot getSignedEncryptedBallot() { + return signedEncryptedBallot; } public BallotSecrets getSecrets() { @@ -34,8 +36,7 @@ public interface VotingBoothEncryptor { * @param plaintextBallot - all plaintext ballot info of the voter * @return an encryption of the ballot */ - public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot); + public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot) throws SignatureException, IOException; - //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java new file mode 100644 index 0000000..3f3a1b2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -0,0 +1,67 @@ +package meerkat.voting.encryptor; + +import meerkat.crypto.*; +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.security.SignatureException; +import java.util.Random; + +/** + * Created by hai on 07/06/16. + */ +public class VBCryptoManagerImpl implements VBCryptoManager { + + protected final static Logger logger = LoggerFactory.getLogger(VBCryptoManagerImpl.class); + + private final Random random; + private final Encryption encryption; + private final DigitalSignature digitalSignature; + + + public VBCryptoManagerImpl (Random rand, Encryption encryption, DigitalSignature digitalSignature) { + this.random = rand; + this.encryption = encryption; + this.digitalSignature = digitalSignature; + } + + + @Override + public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) throws SignatureException, IOException { + + // TODO: do we seed the random here? + + try { + EncryptionRandomness encryptionRandomness = encryption.generateRandomness(random); + BallotSecrets secrets = BallotSecrets.newBuilder() + .setPlaintextBallot(plaintextBallot) + .setEncryptionRandomness(encryptionRandomness) + .build(); + RerandomizableEncryptedMessage encryptedMessage = encryption.encrypt(plaintextBallot, encryptionRandomness); + EncryptedBallot encBallot = EncryptedBallot.newBuilder() + .setSerialNumber(plaintextBallot.getSerialNumber()) + .setData(encryptedMessage) + .build(); + digitalSignature.updateContent(encBallot); + + SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() + .setEncryptedBallot(encBallot) + .setSignerId(digitalSignature.getSignerID()) + .setSignature(digitalSignature.sign()) + .build(); + + return new EncryptionAndSecrets(signedEncryptedBallot, secrets); + } + catch (IOException e) { + logger.error("encrypt: the encryption component has thrown an exception: " + e); + throw e; + } + catch (SignatureException e) { + logger.error("encrypt: the signature component has thrown an exception: " + e); + throw e; + } + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java deleted file mode 100644 index 51ffef0..0000000 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package meerkat.voting.encryptor; - -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 26/04/16. - */ -public class VBEncryptorImpl implements VotingBoothEncryptor { - - @Override - public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) { - throw new UnsupportedOperationException(); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 8d1f7f1..afbe223 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -15,7 +15,7 @@ public interface BallotOutputDevice { * @param callback - a callback object which expects no return value */ public void commitToBallot(PlaintextBallot plaintextBallot, - EncryptedBallot encryptedBallot, + SignedEncryptedBallot encryptedBallot, FutureCallback callback); /** diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index e1556d6..5d8446e 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -29,18 +29,18 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { @Override public void commitToBallot(PlaintextBallot plaintextBallot, - EncryptedBallot encryptedBallot, + SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("entered method commitToBallot"); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); - long encryptedSerialNumber = encryptedBallot.getSerialNumber(); + long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); if (plaintextSerialNumber != encryptedSerialNumber) { logger.error("plaintext and encryption serial numbers do not match!! plaintext# = " + plaintextSerialNumber + ", ciphertext# = " + encryptedSerialNumber); } - ByteString encryptedData = encryptedBallot.getData().getData(); + ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData(); System.out.println(bytesToString(encryptedData)); callback.onSuccess(null); } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 1ab1574..2f30a80 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -26,6 +26,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { private final int tickDurationInMillisec = 10; private Date startWaitingTime; + private volatile boolean shutDownHasBeenCalled; + + public SystemConsoleUI() { logger = LoggerFactory.getLogger(SystemConsoleUI.class); @@ -36,12 +39,15 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { startWaitingTime = null; Timer timer = new Timer(); timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + + shutDownHasBeenCalled = false; } + @Override public void run () { logger.info("entered the voting flow"); - while (true) { + while (! wasShutDownCalled()) { try { UICommand command = queue.take(); handleSingleCommand(command); @@ -53,6 +59,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + private void handleSingleCommand(UICommand command) { if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { @@ -142,6 +155,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } + catch (VoterCancelException e) { + command.getCallback().onFailure(e); + } catch (IOException e) { String errorMessage = "Channel choice failed due to IOException: " + e; logger.error (errorMessage); @@ -163,6 +179,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } + catch (VoterCancelException e) { + command.getCallback().onFailure(e); + } catch (IOException e) { String errorMessage = "Asking voting questions failed due to IOException: " + e; logger.error (errorMessage); @@ -320,7 +339,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private List askVoterForAnswers(List questions) throws IOException { + private List askVoterForAnswers(List questions) throws VoterCancelException, IOException { assertQuestionsAreValid (questions); @@ -335,7 +354,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { String s = readInputLine(); if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { - return null; + throw new VoterCancelException(); } else if (s.equals("back") || s.equals("b")) { --index; @@ -400,4 +419,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return data.toStringUtf8(); } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index 192dd1c..fccb28e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -16,6 +16,11 @@ public interface VotingBoothUI { AUDIT } + /** + * shut down the UI + */ + public void callShutDown(); + /** * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning * @param callback - a boolean future callback to return when done From 13f8948cfba9ebe914db1d1bf3cf06f85aeeb9fc Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 15 Jun 2016 19:32:05 +0300 Subject: [PATCH 30/66] change the output class to run as a thread. It is now runnable and has its own queue of (also new) OutputCommands, and its own shutdown flag. --- .../src/main/proto/meerkat/voting.proto | 3 +- .../java/meerkat/voting/ToyEncryption.java | 46 ++++ .../java/meerkat/voting/ToySignature.java | 82 +++++++ .../meerkat/voting/VotingBoothToyRun.java | 200 ++++++++++++++++++ .../voting/controller/VotingBoothImpl.java | 41 +++- .../callbacks/OutputDeviceCommitCallback.java | 34 +++ ...java => OutputDeviceFinalizeCallback.java} | 14 +- .../commands/ChooseFinalizeOptionCommand.java | 10 + .../voting/encryptor/VBCryptoManagerImpl.java | 1 - .../voting/output/BallotOutputDevice.java | 1 + .../output/SystemConsoleOutputDevice.java | 132 +++++++++--- .../outputcommands/AuditOutputCommand.java | 22 ++ .../outputcommands/CancelOutputCommand.java | 14 ++ .../outputcommands/CastOutputCommand.java | 14 ++ .../outputcommands/CommitOutputCommand.java | 29 +++ .../output/outputcommands/OutputCommand.java | 16 ++ .../meerkat/voting/ui/SystemConsoleUI.java | 2 +- 17 files changed, 609 insertions(+), 52 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/ToyEncryption.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ToySignature.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java rename voting-booth/src/main/java/meerkat/voting/controller/callbacks/{OutputDeviceCallback.java => OutputDeviceFinalizeCallback.java} (58%) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 6c0b1e2..4edc9f5 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -73,8 +73,7 @@ message EncryptedBallot { message SignedEncryptedBallot { EncryptedBallot encrypted_ballot = 1; - bytes signer_id = 2; - Signature signature = 3; + Signature signature = 2; } message BallotSecrets { diff --git a/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java new file mode 100644 index 0000000..e0089c8 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java @@ -0,0 +1,46 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Random; + +/** + * Created by hai on 07/06/16. + */ +public class ToyEncryption implements Encryption { + + @Override + public RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException { + ByteString cipher = ByteString.copyFromUtf8("Encryption(") + .concat(plaintext.toByteString()) + .concat(ByteString.copyFromUtf8(", Random(")) + .concat(rnd.getData()) + .concat(ByteString.copyFromUtf8("))")); + return RerandomizableEncryptedMessage.newBuilder() + .setData(cipher) + .build(); + } + + @Override + public RerandomizableEncryptedMessage rerandomize + (RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException { + throw new UnsupportedOperationException(); + } + + @Override + public EncryptionRandomness generateRandomness(Random rand) { + ByteBuffer b = ByteBuffer.allocate(4); + b.putInt(rand.nextInt()); + byte[] bArr = b.array(); + ByteString bs = ByteString.copyFrom(bArr); + return EncryptionRandomness.newBuilder() + .setData(bs) + .build(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ToySignature.java b/voting-booth/src/main/java/meerkat/voting/ToySignature.java new file mode 100644 index 0000000..e2473c9 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToySignature.java @@ -0,0 +1,82 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +/** + * Created by hai on 07/06/16. + */ +public class ToySignature implements DigitalSignature { + + private final ByteString signerID; + private ByteString msgByteString; + + + public ToySignature(String signerID) { + this.signerID = ByteString.copyFromUtf8(signerID); + } + + @Override + public ByteString getSignerID() { + return signerID; + } + + @Override + public void updateContent(Message msg) throws SignatureException { + msgByteString = msg.toByteString(); + } + + @Override + public Signature sign() throws SignatureException { + ByteString signature = ByteString.copyFromUtf8("Signature(") + .concat(msgByteString) + .concat(ByteString.copyFromUtf8(")")); + return Signature.newBuilder() + .setType(SignatureType.ECDSA) + .setData(signature) + .setSignerId(getSignerID()) + .build(); + } + + + @Override + public void loadVerificationCertificates(InputStream certStream) throws CertificateException { + throw new UnsupportedOperationException(); + } + + @Override + public void clearVerificationCertificates() { + throw new UnsupportedOperationException(); + } + + @Override + public void initVerify(Signature sig) throws CertificateException, InvalidKeyException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean verify() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { + throw new UnsupportedOperationException(); + } + + + @Override + public void clearSigningKey() { + throw new UnsupportedOperationException(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java new file mode 100644 index 0000000..bf466f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -0,0 +1,200 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.*; +import meerkat.voting.controller.selector.SimpleListCategoriesSelector; +import meerkat.voting.output.*; +import meerkat.voting.storage.*; +import meerkat.voting.encryptor.*; +import meerkat.voting.ui.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by hai on 26/04/16. + */ +public class VotingBoothToyRun { + + public static void main(String[] args) { + + Random rand = new Random(); + Encryption enc = new ToyEncryption(); + DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); + + StorageManager storageManager = new StorageManagerMockup(); + SystemConsoleOutputDevice outputDevice = new SystemConsoleOutputDevice(); + VBCryptoManager cryptoManager = new VBCryptoManagerImpl(rand, enc, sig); + SystemConsoleUI ui = new SystemConsoleUI (); + + + VotingBoothImpl controller = new VotingBoothImpl(); + controller.init(outputDevice, cryptoManager, ui, storageManager); + + generateDemoQuestions(controller); + + // create threads + + + Thread controllerThread = new Thread(controller); + controllerThread.setName("Meerkat VB-Controller Thread"); + Thread uiThread = new Thread(ui); + uiThread.setName("Meerkat VB-UI Thread"); + Thread outputThread = new Thread(outputDevice); + uiThread.setName("Meerkat VB-Output Thread"); + + uiThread.start(); + controllerThread.start(); + outputThread.start(); + + } + + + private static void generateDemoQuestions(VotingBoothController controller) { + + List channelChoiceQuestions = generateCahnnelChoiceQuestions(); + controller.setBallotChannelChoiceQuestions(channelChoiceQuestions); + + List allBallotQuestions = generateBallotQuestions(); + controller.setBallotRaceQuestions(allBallotQuestions); + + SimpleCategoriesSelectionData selectionData = generateSelectionData(); + SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData); + controller.setChannelQuestionSelector(selector); + } + + + private static List generateCahnnelChoiceQuestions() { + ArrayList channelChoiceQuestions = new ArrayList(); + + String[] ans1 = {"Red", "Blue", "Green"}; + BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1); + channelChoiceQuestions.add(ccquestion1); + + String[] ans2 = {"Yes", "No"}; + BallotQuestion ccquestion2 = generateBallotQuestion("Are you a republican?", "Pick one answer", ans2); + channelChoiceQuestions.add(ccquestion2); + + return channelChoiceQuestions; + } + + + private static List generateBallotQuestions() { + ArrayList allBallotQuestions = new ArrayList(); + + String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"}; + allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1)); + + String[] answers2 = {"Miranda Kerr", "Doutzen Kroes", "Moran Atias", "Roslana Rodina", "Adriana Lima"}; + allBallotQuestions.add(generateBallotQuestion("question 2: Which model do you like", "Mark as many as you want", answers2)); + + allBallotQuestions.add(generateBallotQuestion("question 3. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 4. Asking something...", "Pick one answer", answers1)); + + String[] answers5 = {"Clint Eastwood", "Ninja", "Sonic", "Tai-chi", "Diablo", "Keanu"}; + allBallotQuestions.add(generateBallotQuestion("question 5: Good name for a cat", "Pick the best one", answers5)); + + allBallotQuestions.add(generateBallotQuestion("question 6. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 7. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 8. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 9. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 10. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 11. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 12. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 13. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 14. Asking something...", "Pick one answer", answers1)); + + return allBallotQuestions; + } + + + private static BallotQuestion generateBallotQuestion(String questionStr, String descriptionStr, String[] answers) { + UIElement question = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(questionStr)) + .build(); + + UIElement description = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(descriptionStr)) + .build(); + + BallotQuestion.Builder bqb = BallotQuestion.newBuilder(); + bqb.setIsMandatory(false); + bqb.setQuestion(question); + bqb.setDescription(description); + for (String answerStr : answers) { + UIElement answer = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(answerStr)) + .build(); + bqb.addAnswer(answer); + } + + return bqb.build(); + } + + + private static SimpleCategoriesSelectionData generateSelectionData() { + Category sharedDefaults = Category.newBuilder() + .addQuestionIndex(0) + .addQuestionIndex(5) + .addQuestionIndex(9) + .build(); + + Category cat00 = Category.newBuilder() + .addQuestionIndex(1) + .addQuestionIndex(4) + .addQuestionIndex(6) + .addQuestionIndex(7) + .build(); + + Category cat01 = Category.newBuilder() + .addQuestionIndex(2) + .addQuestionIndex(4) + .addQuestionIndex(8) + .build(); + + Category cat02 = Category.newBuilder() + .addQuestionIndex(3) + .addQuestionIndex(8) + .build(); + + Category cat10 = Category.newBuilder() + .addQuestionIndex(10) + .addQuestionIndex(11) + .build(); + + Category cat11 = Category.newBuilder() + .addQuestionIndex(12) + .addQuestionIndex(13) + .build(); + + CategoryChooser catChooser0 = CategoryChooser.newBuilder() + .addCategory(cat00) + .addCategory(cat01) + .addCategory(cat02) + .build(); + + CategoryChooser catChooser1 = CategoryChooser.newBuilder() + .addCategory(cat10) + .addCategory(cat11) + .build(); + + return SimpleCategoriesSelectionData.newBuilder() + .setSharedDefaults(sharedDefaults) + .addCategoryChooser(catChooser0) + .addCategoryChooser(catChooser1) + .build(); + + } + private static ByteString stringToBytes (String s) { + return ByteString.copyFromUtf8(s); + } + + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 2d79d33..a9221bf 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -108,6 +108,7 @@ public class VotingBoothImpl implements VotingBoothController { shutDownHasBeenCalled = true; queue.clear(); ui.callShutDown(); + outputDevice.callShutDown(); } private void handleSingleTask (ControllerCommand task) { @@ -122,18 +123,21 @@ public class VotingBoothImpl implements VotingBoothController { if (task instanceof RestartVotingCommand) { doRestartVoting (); } - else if (task instanceof CastCommand) { - doFinalize(false); - } - else if (task instanceof AuditCommand) { - doFinalize(true); - } else if (task instanceof ChannelChoiceCommand) { doChooseChannel(); } else if (task instanceof ChannelDeterminedCommand) { doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); } + else if (task instanceof ChooseFinalizeOptionCommand) { + doChooseFinalizeOption(); + } + else if (task instanceof CastCommand) { + doFinalize(false); + } + else if (task instanceof AuditCommand) { + doFinalize(true); + } else if (task instanceof EncryptAndCommitBallotCommand) { doCommit ((EncryptAndCommitBallotCommand)task); } @@ -213,6 +217,19 @@ public class VotingBoothImpl implements VotingBoothController { } + private void doChooseFinalizeOption() { + if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) { + logger.debug("doChooseFinalizeOption"); + state.stateIdentifier = VBState.CAST_OR_AUDIT; + ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); + } + else { + logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); + // ignore this request + } + } private void doCommit (EncryptAndCommitBallotCommand task) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); @@ -224,7 +241,7 @@ public class VotingBoothImpl implements VotingBoothController { this.queue)); outputDevice.commitToBallot(state.plaintextBallot, state.signedEncryptedBallot, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { logger.debug("doCommit: current state is " + state.stateIdentifier); @@ -252,15 +269,17 @@ public class VotingBoothImpl implements VotingBoothController { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); if (auditRequested) { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.audit(state.secrets, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.castBallot( - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } } else { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java new file mode 100644 index 0000000..a6eaadf --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -0,0 +1,34 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.SystemMessages; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class OutputDeviceCommitCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); + + public OutputDeviceCommitCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Void v) { + logger.debug("callback for output device commit success"); + enqueueCommand(new ChooseFinalizeOptionCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("OutputDeviceCommitCallback got a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getOutputDeviceFailureMessage())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java similarity index 58% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 2432f49..74a85e0 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -9,22 +9,24 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class OutputDeviceCallback extends ControllerCallback { - protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); +public class OutputDeviceFinalizeCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); - public OutputDeviceCallback(int requestId, - long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + public OutputDeviceFinalizeCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { super(requestId, ballotSerialNumber, controllerQueue); } @Override public void onSuccess(Void v) { + logger.debug("callback for output device finalize success"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } @Override public void onFailure(Throwable t) { - logger.error("WaitForFinishCallback got a failure: " + t); + logger.error("OutputDeviceFinalizeCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), SystemMessages.getOutputDeviceFailureMessage())); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java new file mode 100644 index 0000000..76b0e77 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ChooseFinalizeOptionCommand extends ControllerCommand { + public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 3f3a1b2..722c24e 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -49,7 +49,6 @@ public class VBCryptoManagerImpl implements VBCryptoManager { SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() .setEncryptedBallot(encBallot) - .setSignerId(digitalSignature.getSignerID()) .setSignature(digitalSignature.sign()) .build(); diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index afbe223..97fa7ed 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -37,4 +37,5 @@ public interface BallotOutputDevice { */ public void cancelBallot(FutureCallback callback); + public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 5d8446e..614dc40 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -4,22 +4,31 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.LinkedBlockingQueue; + /** * A toy OutputDevice class * outputs everything simply to the System console */ -public class SystemConsoleOutputDevice implements BallotOutputDevice { +public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; public SystemConsoleOutputDevice () { logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; } + /* * Returns the UTF8 decoding of byte-string data */ @@ -27,13 +36,69 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { return data.toStringUtf8(); } + @Override + public void run () { + logger.info("UI starts running"); + while (! wasShutDownCalled()) { + try { + OutputCommand command = queue.take(); + handleSingleCommand(command); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from command queue " + e); + } + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + + + private void handleSingleCommand(OutputCommand command) { + if (command instanceof CommitOutputCommand) { + doCommitToBallot((CommitOutputCommand)command); + } + else if (command instanceof AuditOutputCommand) { + doAudit((AuditOutputCommand)command); + } + else if (command instanceof CastOutputCommand) { + doCastBallot((CastOutputCommand)command); + } + else if (command instanceof CancelOutputCommand) { + doCancel((CancelOutputCommand)command); + } + else { + String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + @Override public void commitToBallot(PlaintextBallot plaintextBallot, SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { - logger.debug("entered method commitToBallot"); + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + PlaintextBallot plaintextBallot = command.getPlaintext(); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + System.out.println(plaintextBallot); + SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot(); long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); if (plaintextSerialNumber != encryptedSerialNumber) { @@ -42,33 +107,52 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { } ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData(); System.out.println(bytesToString(encryptedData)); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } + @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { - logger.debug("entered method audit"); + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); System.out.println("Auditing"); - printPlaintextBallot (ballotSecrets.getPlaintextBallot()); + BallotSecrets ballotSecrets = command.getBallotSecrets(); printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); printRandomnessGenerationProof (ballotSecrets.getProof()); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } - private void printPlaintextBallot (PlaintextBallot plaintextBallot) { - long plaintextSerialNumber = plaintextBallot.getSerialNumber(); - System.out.println("Plaintext serial number = " + plaintextSerialNumber); - System.out.println("Answers = "); - for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) { - String printableAnswer = ""; - for (long n : ballotAnswer.getAnswerList()) { - printableAnswer += n + " "; - } - System.out.println(printableAnswer); - } + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); } + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + System.out.println("Ballot finalized for casting!"); + command.getCallback().onSuccess(null); + } + + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + System.out.println("Ballot cancelled!"); + command.getCallback().onSuccess(null); + } + + private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) { System.out.println("Encryption Randomness = "); ByteString data = encryptionRandomness.getData(); @@ -81,18 +165,4 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { System.out.println(bytesToString(data)); } - - @Override - public void castBallot(FutureCallback callback) { - logger.debug("entered method castBallot"); - System.out.println("Ballot finalized for casting!"); - callback.onSuccess(null); - } - - @Override - public void cancelBallot(FutureCallback callback) { - logger.debug("entered method cancelBallot"); - System.out.println("Ballot cancelled!"); - callback.onSuccess(null); - } } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java new file mode 100644 index 0000000..2722326 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class AuditOutputCommand extends OutputCommand { + + private final BallotSecrets ballotSecrets; + + public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { + super(callback); + this.ballotSecrets = ballotSecrets; + } + + public BallotSecrets getBallotSecrets() { + return ballotSecrets; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java new file mode 100644 index 0000000..0c360d2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CancelOutputCommand extends OutputCommand { + + public CancelOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java new file mode 100644 index 0000000..af7ed30 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CastOutputCommand extends OutputCommand { + + public CastOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java new file mode 100644 index 0000000..dcd52f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -0,0 +1,29 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CommitOutputCommand extends OutputCommand { + + private final PlaintextBallot plaintextBallot; + private final SignedEncryptedBallot signedEncryptedBallot; + + public CommitOutputCommand(PlaintextBallot plaintextBallot, + SignedEncryptedBallot signedEncryptedBallot, + ControllerCallback callback) { + super(callback); + this.plaintextBallot = plaintextBallot; + this.signedEncryptedBallot = signedEncryptedBallot; + } + + public PlaintextBallot getPlaintext() { + return plaintextBallot; + } + + public SignedEncryptedBallot getSignedEncryptedBallot() { + return signedEncryptedBallot; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java new file mode 100644 index 0000000..8a7c322 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +//TODO: make this class generic +public abstract class OutputCommand { + protected final ControllerCallback callback; + + protected OutputCommand(ControllerCallback callback) { + this.callback = callback; + } + + public ControllerCallback getCallback () { + return this.callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 2f30a80..bc3ac92 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -46,7 +46,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void run () { - logger.info("entered the voting flow"); + logger.info("UI starts running"); while (! wasShutDownCalled()) { try { UICommand command = queue.take(); From 2bdf92b075772492376e74436602503831d495c9 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 20 Jun 2016 15:26:53 +0300 Subject: [PATCH 31/66] Fixed some stuff according to Arbel's suggestions. Specifically: 1. now handling exceptions in the encryption process (according to voter's choice) 2. handling files in storage manager (now reading election parameters and system messages from files) 3. Controller's init() now already sets all the info and parameters. No need to call extra functions 4. some more changes to the method structure --- .../src/main/proto/meerkat/voting.proto | 17 +- .../voting/controller/SystemMessages.java | 7 - .../controller/VotingBoothController.java | 21 +-- .../voting/controller/VotingBoothImpl.java | 166 +++++++++++------- .../callbacks/CastOrAuditCallback.java | 12 +- .../callbacks/ChannelChoiceCallback.java | 8 +- .../callbacks/EncryptionFailedCallback.java | 43 +++++ .../callbacks/OutputDeviceCommitCallback.java | 9 +- .../OutputDeviceFinalizeCallback.java | 9 +- .../controller/callbacks/VotingCallback.java | 8 +- .../callbacks/WaitForFinishCallback.java | 10 +- .../EncryptAndCommitBallotCommand.java | 8 +- .../RetryEncryptAndCommitBallotCommand.java | 10 ++ .../voting/encryptor/VBCryptoManager.java | 1 + .../voting/encryptor/VBCryptoManagerImpl.java | 2 + .../voting/storage/StorageManager.java | 17 ++ .../voting/storage/StorageManagerMockup.java | 25 ++- 17 files changed, 256 insertions(+), 117 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 4edc9f5..09c8b21 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -88,6 +88,10 @@ message BoothParams { } +message BoothSystemMessages { + map system_message = 1; +} + // A table to translate to and from compactly encoded answers // and their human-understandable counterparts. // This should be parsable by the UI @@ -122,14 +126,17 @@ message ElectionParams { // How many mixers must participate for the mixing to be considered valid uint32 mixerThreshold = 5; - // Candidate list (or other question format) - repeated BallotQuestion questions = 6; + // questions to first indicate the voter's channel + repeated BallotQuestion channel_choice_questions = 6; - // Translation table between answers and plaintext encoding - //BallotAnswerTranslationTable answerTranslationTable = 7; + // translating the channel-choice answers to the voter's channel + SimpleCategoriesSelectionData selection_data = 7; + + // Candidate list (or other question format) + repeated BallotQuestion race_questions = 8; // Data required in order to access the Bulletin Board Servers - BulletinBoardClientParams bulletinBoardClientParams = 8; + BulletinBoardClientParams bulletinBoardClientParams = 9; } message Category { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java index ee6b506..4f57809 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java @@ -33,13 +33,6 @@ final public class SystemMessages { .build(); } - public static UIElement getFatalForceRestartMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Fatal error: Internal controller queue received unrecognized command. Force restarting the voting process.")) - .build(); - } - public static UIElement getRestartVotingButton() { return UIElement.newBuilder() .setType(UIElementDataType.TEXT) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index 6b706f3..e8eae93 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -7,6 +7,7 @@ import meerkat.voting.ui.VotingBoothUI; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; +import java.io.IOException; import java.util.List; @@ -25,25 +26,7 @@ public interface VotingBoothController extends Runnable{ public void init (BallotOutputDevice outputDevice, VBCryptoManager vbCrypto, VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * set the voting questions - * @param questions - */ - public void setBallotChannelChoiceQuestions(List questions); - - /** - * Set the channel question-selector (the component which matches the ballot questions to each user) - * @param selector the question selector instance - */ - public void setChannelQuestionSelector (QuestionSelector selector); - - /** - * set the voting race questions - * @param questions - */ - public void setBallotRaceQuestions(List questions); + StorageManager vbStorageManager) throws IOException; /** * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index a9221bf..b20a11d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,9 +1,11 @@ package meerkat.voting.controller; +import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.controller.selector.SimpleListCategoriesSelector; import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.encryptor.VBCryptoManager.EncryptionAndSecrets; import meerkat.voting.output.BallotOutputDevice; @@ -15,6 +17,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.security.SignatureException; import java.util.List; +import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; /** @@ -29,6 +32,7 @@ public class VotingBoothImpl implements VotingBoothController { private List questionsForChoosingChannel; private List questions; private QuestionSelector questionSelector; + private Map systemMessages; private LinkedBlockingQueue queue; @@ -41,6 +45,7 @@ public class VotingBoothImpl implements VotingBoothController { private static int requestCounter = 0; + public VotingBoothImpl () { logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); @@ -53,30 +58,32 @@ public class VotingBoothImpl implements VotingBoothController { public void init(BallotOutputDevice outputDevice, VBCryptoManager vbCrypto, VotingBoothUI vbUI, - StorageManager vbStorageManager) { + StorageManager vbStorageManager) throws IOException { logger.info("init is called"); this.outputDevice = outputDevice; this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; + + ElectionParams electionParams; + try { + logger.info("init: reading election params"); + electionParams = storageManager.readElectionParams(); + logger.info("init: reading system messages"); + systemMessages = storageManager.readSystemMessages(); + } + catch (IOException e) { + logger.error("init could not read info from a file. Exception is: " + e); + throw e; + } + + logger.info("init: setting the election parameters"); + this.questionsForChoosingChannel = electionParams.getChannelChoiceQuestionsList(); + this.questions = electionParams.getRaceQuestionsList(); + this.questionSelector = new SimpleListCategoriesSelector(this.questions, electionParams.getSelectionData()); + logger.info("init: setting finished"); } - @Override - public void setBallotChannelChoiceQuestions(List questions) { - logger.info("setting questions"); - this.questionsForChoosingChannel = questions; - } - - @Override - public void setChannelQuestionSelector(QuestionSelector selector) { - this.questionSelector = selector; - } - - @Override - public void setBallotRaceQuestions(List questions) { - logger.info("setting questions"); - this.questions = questions; - } @Override public void run() { @@ -146,7 +153,7 @@ public class VotingBoothImpl implements VotingBoothController { } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); - doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); + doReportErrorAndForceRestart(systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -156,18 +163,13 @@ public class VotingBoothImpl implements VotingBoothController { private void doShutDown () { logger.info("running callShutDown"); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.SHUT_DOWN; + state.clearAndResetState(VBState.SHUT_DOWN); //TODO: add commands to actually shut down the machine } private void doRestartVoting () { queue.clear(); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.NEW_VOTER; - state.currentBallotSerialNumber += 1; + state.clearAndResetState(VBState.NEW_VOTER); ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } @@ -178,13 +180,12 @@ public class VotingBoothImpl implements VotingBoothController { private void doReportErrorAndForceRestart(UIElement errorMessage) { queue.clear(); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.FATAL_ERROR_FORCE_NEW_VOTER; - state.currentBallotSerialNumber += 1; + state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); ui.showErrorMessageWithButtons(errorMessage, - new UIElement[]{SystemMessages.getRestartVotingButton()}, - new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new UIElement[]{systemMessages.get(storageManager.RESTART_VOTING_BUTTON)}, + new ErrorMessageRestartCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); } private void doChooseChannel () { @@ -192,7 +193,10 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("doing chooseChannel"); state.stateIdentifier = VBState.CHOOSE_CHANNEL; ui.chooseChannel(this.questionsForChoosingChannel, - new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new ChannelChoiceCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); } else { logger.debug("doChooseChannel: current state is " + state.stateIdentifier); @@ -208,7 +212,10 @@ public class VotingBoothImpl implements VotingBoothController { state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, - new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new VotingCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.UNSUCCESSFUL_VOTING_MESSAGE))); } else { logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); @@ -223,7 +230,8 @@ public class VotingBoothImpl implements VotingBoothController { state.stateIdentifier = VBState.CAST_OR_AUDIT; ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, - this.queue)); + this.queue, + systemMessages.get(storageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); } else { logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); @@ -233,15 +241,33 @@ public class VotingBoothImpl implements VotingBoothController { private void doCommit (EncryptAndCommitBallotCommand task) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); - state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; - setBallotData (task); - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), - state.currentBallotSerialNumber, - this.queue)); - outputDevice.commitToBallot(state.plaintextBallot, - state.signedEncryptedBallot, - new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + try { + setBallotData(task); + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_COMMIT_MESSAGE), + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + outputDevice.commitToBallot(state.plaintextBallot, + state.signedEncryptedBallot, + new OutputDeviceCommitCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; + } + catch (SignatureException | IOException e) { + logger.error("doCommit: encryption failed. exception: " + e); + UIElement errorMessage = systemMessages.get(storageManager.ENCRYPTION_FAILED_MESSAGE); + UIElement[] buttons = new UIElement[]{ + systemMessages.get(storageManager.RETRY_BUTTON), + systemMessages.get(storageManager.CANCEL_VOTE_BUTTON)}; + + EncryptionFailedCallback callback = new EncryptionFailedCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue); + ui.showErrorMessageWithButtons(errorMessage, buttons, callback); + } } else { logger.debug("doCommit: current state is " + state.stateIdentifier); @@ -249,18 +275,16 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void setBallotData (EncryptAndCommitBallotCommand task) { - state.plaintextBallot = PlaintextBallot.newBuilder() - .setSerialNumber(task.getBallotSerialNumber()) - .addAllAnswers(task.getVotingAnswers()) - .build(); - EncryptionAndSecrets encryptionAndSecrets = null; - try { - encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); - } - catch (SignatureException | IOException e) { - // TODO: handle exception + private void setBallotData (EncryptAndCommitBallotCommand task) throws IOException, SignatureException{ + if (! (task instanceof RetryEncryptAndCommitBallotCommand)) { + // this is not a retry attempt, so the plaintext is not set yet + // otherwise, we have the plaintext from the previous encryption attempt + state.plaintextBallot = PlaintextBallot.newBuilder() + .setSerialNumber(task.getBallotSerialNumber()) + .addAllAnswers(task.getVotingAnswers()) + .build(); } + EncryptionAndSecrets encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } @@ -270,16 +294,28 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_AUDIT_MESSAGE), + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.audit(state.secrets, - new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.castBallot( - new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } } else { @@ -325,14 +361,22 @@ public class VotingBoothImpl implements VotingBoothController { } - public void clearPlaintext () { + private void clearPlaintext () { plaintextBallot = null; } - public void clearCiphertext () { + private void clearCiphertext () { signedEncryptedBallot = null; secrets = null; } + + public void clearAndResetState(VBState newStateIdentifier) { + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = newStateIdentifier; + state.currentBallotSerialNumber += 1; + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 69d5123..47ecd3b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -1,9 +1,8 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; import meerkat.voting.ui.VotingBoothUI.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); + protected final UIElement unrecognizedFinalizeResponseMessage; public CastOrAuditCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unrecognizedFinalizeResponseMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unrecognizedFinalizeResponseMessage = unrecognizedFinalizeResponseMessage; } @Override @@ -31,7 +33,7 @@ public class CastOrAuditCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); + protected final UIElement unsuccessfulChannelChoiceMessage; public ChannelChoiceCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unsuccessfulChannelChoiceMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unsuccessfulChannelChoiceMessage = unsuccessfulChannelChoiceMessage; } @Override @@ -37,7 +39,7 @@ public class ChannelChoiceCallback extends ControllerCallback logger.error("channel choice initiated a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getUnsuccessfulChannelChoiceMessage())); + unsuccessfulChannelChoiceMessage)); } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java new file mode 100644 index 0000000..de7a61e --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java @@ -0,0 +1,43 @@ +package meerkat.voting.controller.callbacks; + +import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.RetryEncryptAndCommitBallotCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class EncryptionFailedCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(EncryptionFailedCallback.class); + + public EncryptionFailedCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Integer result) { + logger.debug("callback for voting returned success"); + int res = result.intValue(); + if (res == 0) { + logger.debug("voter chose to retry encryption"); + enqueueCommand(new RetryEncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else if (res == 1) { + logger.debug("voter chose to cancel the vote"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + onFailure(new ValueException("EncryptionFailedCallback got an unknown result (" + res + ")")); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("Error message execution initiated a failure: " + t); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java index a6eaadf..a832572 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; import meerkat.voting.controller.commands.ReportErrorCommand; @@ -11,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class OutputDeviceCommitCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); + protected final UIElement outputDeviceFailureMessage; public OutputDeviceCommitCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement outputDeviceFailureMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.outputDeviceFailureMessage = outputDeviceFailureMessage; } @Override @@ -29,6 +32,6 @@ public class OutputDeviceCommitCallback extends ControllerCallback { logger.error("OutputDeviceCommitCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getOutputDeviceFailureMessage())); + outputDeviceFailureMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 74a85e0..414bdb0 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; @@ -11,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class OutputDeviceFinalizeCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); + protected final UIElement outputDeviceFailureMessage; public OutputDeviceFinalizeCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement outputDeviceFailureMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.outputDeviceFailureMessage = outputDeviceFailureMessage; } @Override @@ -29,6 +32,6 @@ public class OutputDeviceFinalizeCallback extends ControllerCallback { logger.error("OutputDeviceFinalizeCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getOutputDeviceFailureMessage())); + outputDeviceFailureMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 4b6f2f7..173fa82 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,7 +1,6 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; import meerkat.voting.controller.commands.ReportErrorCommand; @@ -14,11 +13,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); + protected final UIElement unsuccessfulVotingMessage; public VotingCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unsuccessfulVotingMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unsuccessfulVotingMessage = unsuccessfulVotingMessage; } @Override @@ -37,7 +39,7 @@ public class VotingCallback extends ControllerCallback> { logger.error("voting initiated a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getUnsuccessfulVotingMessage())); + unsuccessfulVotingMessage)); } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index 9f7a159..2634e27 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,9 +1,8 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,11 +10,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); + protected final UIElement somethingWrongMessage; public WaitForFinishCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement somethingWrongMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.somethingWrongMessage = somethingWrongMessage; } @Override @@ -27,6 +29,6 @@ public class WaitForFinishCallback extends ControllerCallback { logger.error("WaitForFinishCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getSomethingWrongMessage())); + somethingWrongMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index 074216f..d7e4508 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -1,13 +1,14 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting.*; - +import meerkat.protobuf.Voting.BallotAnswer; import java.util.List; public class EncryptAndCommitBallotCommand extends ControllerCommand { private final List votingAnswers; - public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, List answers) { + public EncryptAndCommitBallotCommand(int requestIdentifier, + long ballotSerialNumber, + List answers) { super(requestIdentifier, ballotSerialNumber); votingAnswers = answers; } @@ -15,4 +16,5 @@ public class EncryptAndCommitBallotCommand extends ControllerCommand { public List getVotingAnswers() { return votingAnswers; } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java new file mode 100644 index 0000000..66dc992 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +public class RetryEncryptAndCommitBallotCommand extends EncryptAndCommitBallotCommand { + + public RetryEncryptAndCommitBallotCommand(int requestIdentifier, + long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber, null); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index e664607..d5216e4 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -36,6 +36,7 @@ public interface VBCryptoManager { * @param plaintextBallot - all plaintext ballot info of the voter * @return an encryption of the ballot */ + // TODO: do we seed the random here? public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot) throws SignatureException, IOException; diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 722c24e..2bc9729 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -52,6 +52,8 @@ public class VBCryptoManagerImpl implements VBCryptoManager { .setSignature(digitalSignature.sign()) .build(); + // TODO: still has to supply RandomnessGenerationProof as well + return new EncryptionAndSecrets(signedEncryptedBallot, secrets); } catch (IOException e) { diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index 9bf7764..b9ccca7 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -3,6 +3,7 @@ package meerkat.voting.storage; import meerkat.protobuf.Voting.*; import java.io.IOException; +import java.util.Map; /** * An interface for the storage component of the voting booth @@ -29,4 +30,20 @@ public interface StorageManager { */ public void writeElectionParams(ElectionParams params) throws IOException; + + public Map readSystemMessages() throws IOException; + + + public final static String WAIT_FOR_COMMIT_MESSAGE = "waitForCommit"; + public final static String WAIT_FOR_AUDIT_MESSAGE = "waitForAudit"; + public final static String WAIT_FOR_CAST_MESSAGE = "waitForCast"; + public final static String RESTART_VOTING_BUTTON = "restartVotingButton"; + public final static String UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE = "unrecognizedFinalizeResponse"; + public final static String UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE = "unsuccessfulChannelChoice"; + public final static String OUTPUT_DEVICE_FAILURE_MESSAGE = "outputDeviceFailure"; + public final static String UNSUCCESSFUL_VOTING_MESSAGE = "unsuccessfulVoting"; + public final static String SOMETHING_WRONG_MESSAGE = "somethingWrong"; + public final static String ENCRYPTION_FAILED_MESSAGE = "encryptionFailed"; + public final static String RETRY_BUTTON = "retryButton"; + public final static String CANCEL_VOTE_BUTTON = "cancelVoteButton"; } diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java index 23c89cf..ea9ac08 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -1,5 +1,6 @@ package meerkat.voting.storage; +import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -7,6 +8,8 @@ import org.slf4j.LoggerFactory; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * A mockup for the StorageManager interface @@ -16,7 +19,8 @@ public class StorageManagerMockup implements StorageManager { private boolean adminHardwareKeyInserted; private Logger logger; - private String electionParamFullFilename = "~/meerkat_election_params_tempfile.dat"; + public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; + public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; public StorageManagerMockup () { logger = LoggerFactory.getLogger(StorageManagerMockup.class); @@ -64,4 +68,23 @@ public class StorageManagerMockup implements StorageManager { } } + + @Override + public Map readSystemMessages() throws IOException { + + logger.info("Entered method readSystemMessages"); + BoothSystemMessages systemMessages; + try { + FileInputStream inputStream = new FileInputStream(systemMessagesFilename); + systemMessages = BoothSystemMessages.parseFrom(inputStream); + inputStream.close(); + logger.info ("Successfully read systemMessages protobuf from a file"); + } + catch (IOException e) { + logger.error("Could not read from the systemMessages file: '" + systemMessagesFilename + "'."); + throw e; + } + return systemMessages.getSystemMessage(); + } + } From 559c714aacda0248736abe05d2078de1db1ce91e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 20 Jun 2016 15:27:39 +0300 Subject: [PATCH 32/66] testing was changed according to the new interface of storage manager --- .../meerkat/voting/VotingBoothToyRun.java | 120 +++++++++++++++--- 1 file changed, 105 insertions(+), 15 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java index bf466f6..dfd9b6a 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -5,15 +5,14 @@ import meerkat.crypto.DigitalSignature; import meerkat.crypto.Encryption; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.*; -import meerkat.voting.controller.selector.SimpleListCategoriesSelector; import meerkat.voting.output.*; import meerkat.voting.storage.*; import meerkat.voting.encryptor.*; import meerkat.voting.ui.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; /** * Created by hai on 26/04/16. @@ -22,6 +21,14 @@ public class VotingBoothToyRun { public static void main(String[] args) { + try { + generateSystemMessages(); + generateDemoQuestions(); + } + catch (Exception e) { + return; + } + Random rand = new Random(); Encryption enc = new ToyEncryption(); DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); @@ -33,9 +40,15 @@ public class VotingBoothToyRun { VotingBoothImpl controller = new VotingBoothImpl(); - controller.init(outputDevice, cryptoManager, ui, storageManager); - generateDemoQuestions(controller); + try { + controller.init(outputDevice, cryptoManager, ui, storageManager); + } + catch (Exception e) { + System.err.println("init failed"); + return; + } + // create threads @@ -54,21 +67,29 @@ public class VotingBoothToyRun { } - private static void generateDemoQuestions(VotingBoothController controller) { + private static void generateDemoQuestions() throws IOException { - List channelChoiceQuestions = generateCahnnelChoiceQuestions(); - controller.setBallotChannelChoiceQuestions(channelChoiceQuestions); + ElectionParams electionParams = ElectionParams.newBuilder() + .addAllRaceQuestions(generateBallotQuestions()) + .addAllChannelChoiceQuestions(generateChannelChoiceQuestions()) + .setSelectionData(generateSelectionData()) + .build(); - List allBallotQuestions = generateBallotQuestions(); - controller.setBallotRaceQuestions(allBallotQuestions); + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.electionParamFullFilename); + electionParams.writeTo(output); + output.close(); + System.out.println("Successfully wrote election parameter protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the election parameter file: '" + StorageManagerMockup.electionParamFullFilename + "'."); + throw e; + } - SimpleCategoriesSelectionData selectionData = generateSelectionData(); - SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData); - controller.setChannelQuestionSelector(selector); } - private static List generateCahnnelChoiceQuestions() { + private static List generateChannelChoiceQuestions() { ArrayList channelChoiceQuestions = new ArrayList(); String[] ans1 = {"Red", "Blue", "Green"}; @@ -192,9 +213,78 @@ public class VotingBoothToyRun { .build(); } + + + private static ByteString stringToBytes (String s) { return ByteString.copyFromUtf8(s); } + private static void generateSystemMessages() throws IOException{ + Map systemMessageMap = new HashMap(); + + systemMessageMap.put(StorageManager.WAIT_FOR_COMMIT_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_AUDIT_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_CAST_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build()); + systemMessageMap.put(StorageManager.RESTART_VOTING_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Restart voting")) + .build()); + systemMessageMap.put(StorageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_VOTING_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.SOMETHING_WRONG_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.ENCRYPTION_FAILED_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Encryption failed for some unknown reason.")) + .build()); + systemMessageMap.put(StorageManager.RETRY_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Retry")) + .build()); + systemMessageMap.put(StorageManager.CANCEL_VOTE_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Cancel Vote")) + .build()); + + BoothSystemMessages systemMessages = BoothSystemMessages.newBuilder().putAllSystemMessage(systemMessageMap).build(); + + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.systemMessagesFilename); + systemMessages.writeTo(output); + output.close(); + System.out.println("Successfully wrote system messages protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the system messages file: '" + StorageManagerMockup.systemMessagesFilename + "'."); + throw e; + } + + } } From 19deec00bbe2138d1220e72767df1edbdb0ef192 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 20 Jun 2016 16:15:41 +0300 Subject: [PATCH 33/66] a change of variable name to suggest its insignificance --- .../controller/callbacks/ErrorMessageRestartCallback.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java index 34f1194..fae8b4e 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -17,7 +17,7 @@ public class ErrorMessageRestartCallback extends ControllerCallback { } @Override - public void onSuccess(Integer result) { + public void onSuccess(Integer i) { enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } From e9732561f44562ae121ddd2819c09e8af3ea2947 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 21 Jun 2016 15:35:42 +0300 Subject: [PATCH 34/66] Removed the last dependency on the obsolete SystemMessages class. This dependency was left by mistake. We now read all the system messages of the VB from a protobuf file using the StorageManager component. --- .../voting/controller/SystemMessages.java | 77 ------------------- .../voting/controller/VotingBoothImpl.java | 2 +- 2 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java deleted file mode 100644 index 4f57809..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java +++ /dev/null @@ -1,77 +0,0 @@ -package meerkat.voting.controller; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 18/05/16. - */ -final public class SystemMessages { - - private SystemMessages() { - // This is a static class. No instantiation of this is needed. - } - - public static UIElement getWaitForCommitMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) - .build(); - } - - public static UIElement getWaitForAuditMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) - .build(); - } - - public static UIElement getWaitForCastMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) - .build(); - } - - public static UIElement getRestartVotingButton() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Restart voting")) - .build(); - } - - public static UIElement getUnrecognizedFinalizeResponseMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) - .build(); - } - - public static UIElement getUnsuccessfulChannelChoiceMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) - .build(); - } - - public static UIElement getOutputDeviceFailureMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) - .build(); - } - - public static UIElement getUnsuccessfulVotingMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) - .build(); - } - - public static UIElement getSomethingWrongMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) - .build(); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index b20a11d..849651f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -306,7 +306,7 @@ public class VotingBoothImpl implements VotingBoothController { systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, From 42ae18df0010a255c5e7d71f6aa50487b2c08d9c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 21 Jun 2016 15:37:20 +0300 Subject: [PATCH 35/66] Just added comments as part of the process to comment all the VB files. Currently I commented the controller callbacks and commands packages, and also the QuestionSelector component. --- .../callbacks/CastOrAuditCallback.java | 11 ++-- .../callbacks/ChannelChoiceCallback.java | 9 ++- .../callbacks/ControllerCallback.java | 12 ++-- .../callbacks/EncryptionFailedCallback.java | 18 +++--- .../ErrorMessageRestartCallback.java | 10 +++- .../callbacks/NewVoterCallback.java | 11 ++-- .../callbacks/OutputDeviceCommitCallback.java | 10 ++-- .../OutputDeviceFinalizeCallback.java | 10 ++-- .../callbacks/VoterCancelException.java | 4 +- .../controller/callbacks/VotingCallback.java | 13 ++-- .../callbacks/WaitForFinishCallback.java | 9 ++- .../controller/commands/AuditCommand.java | 2 +- .../controller/commands/CastCommand.java | 2 +- .../commands/ChannelChoiceCommand.java | 2 +- .../commands/ChannelDeterminedCommand.java | 2 +- .../commands/ChooseFinalizeOptionCommand.java | 2 +- .../commands/ControllerCommand.java | 4 ++ .../EncryptAndCommitBallotCommand.java | 4 ++ .../commands/ReportErrorCommand.java | 4 ++ .../commands/RestartVotingCommand.java | 3 + .../RetryEncryptAndCommitBallotCommand.java | 5 ++ .../controller/selector/QuestionSelector.java | 16 ++++- .../SimpleListCategoriesSelector.java | 59 +++++++++++++++++-- 23 files changed, 168 insertions(+), 54 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 47ecd3b..7226f83 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -2,13 +2,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.*; -import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.ui.VotingBoothUI.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the cast-or-audit request to the UI. + * Upon getting a FinalizeBallotChoice response from the voter, the callback then registers a new command + * to the controller queue, either a CastCommand or an AuditCommand according to the voter's choice + */ public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); protected final UIElement unrecognizedFinalizeResponseMessage; @@ -31,9 +34,7 @@ public class CastOrAuditCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); @@ -26,12 +29,14 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onSuccess(List result) { logger.debug("callback for channel choice returned success"); + // register the chosen BallotAnswers to a command in the controller queue enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { if (t instanceof VoterCancelException) { + // voter has cancelled during the UI channel choice process. A VoterCancelException is thrown logger.debug("ChannelChoiceCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java index d5684d2..18719bd 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -1,13 +1,17 @@ package meerkat.voting.controller.callbacks; -/** - * Created by hai on 18/05/16. - */ import com.google.common.util.concurrent.FutureCallback; import meerkat.voting.controller.commands.ControllerCommand; - import java.util.concurrent.LinkedBlockingQueue; +/** + * The base (abstract) class of all callbacks for requests sent by the controller to other components (ui, output-device) + * It implements the FutureCallback interface + * Its members are: + * - requestIdentifier - uniquely identifies the request which this callback responds + * - ballotSerialNumber - number of ballot which was currently active when request was sent + * - controllerQueue - so the callback can issue and register a new command to the controller, once the request handling is finished + */ public abstract class ControllerCallback implements FutureCallback { private final int requestIdentifier; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java index de7a61e..55906be 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; -import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; -import meerkat.voting.controller.commands.RetryEncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This is quite a special callback. It is not issued in a normal flow of the voting. + * This callback is made only for a request to the UI to choose handling of failure in encryption. + * When encryption/signature fails the voter is asked in the UI whether to retry or abort. + * This specific callback decides, upon the answer to this request, which command to register in the controller's queue + */ public class EncryptionFailedCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(EncryptionFailedCallback.class); @@ -20,18 +22,18 @@ public class EncryptionFailedCallback extends ControllerCallback { @Override public void onSuccess(Integer result) { - logger.debug("callback for voting returned success"); + logger.debug("callback for encryption-failed request is initiated successfully"); int res = result.intValue(); if (res == 0) { logger.debug("voter chose to retry encryption"); enqueueCommand(new RetryEncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber())); } else if (res == 1) { - logger.debug("voter chose to cancel the vote"); + logger.debug("voter chose to abort the vote"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } else { - onFailure(new ValueException("EncryptionFailedCallback got an unknown result (" + res + ")")); + onFailure(new IllegalArgumentException("EncryptionFailedCallback got an unknown result (" + res + ")")); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java index fae8b4e..4d75c1d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -1,12 +1,16 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This is quite a special callback. It is not issued in a normal flow of the voting. + * This callback is made only for a request to the UI to show the voter an error message. + * Upon approval of the voter, the method onSuccess() of this callback is called, and the voting + * is reset through a command to the controller's queue + */ public class ErrorMessageRestartCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(ErrorMessageRestartCallback.class); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java index 9b4e365..17f67be 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -1,13 +1,16 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.commands.ChannelChoiceCommand; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; + +/** + * A controller callback for the StartSession request to the UI. + * Upon approval of the voter, it registers a new ChannelChoiceCommand to the controller queue (which + * then starts the channel choice process) + */ public class NewVoterCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java index a832572..dd20ec2 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the Commit request to the output-device. + * When committing is done, the callback's onSuccess() method is called to register a new ChooseFinalizeOptionCommand + * to the controller + */ public class OutputDeviceCommitCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); protected final UIElement outputDeviceFailureMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 414bdb0..6c5b0d4 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the Finalize request to the output-device. + * When finalizing (either cast or audit) is done, + * the callback's onSuccess() method is called to register a new command to the controller to restart the voting process + */ public class OutputDeviceFinalizeCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); protected final UIElement outputDeviceFailureMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java index 4c0d411..2844fc1 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java @@ -1,8 +1,8 @@ package meerkat.voting.controller.callbacks; /** - * Created by hai on 06/06/16. + * Just a simple unique exception to throw when a voter aborts/cancels the voting during the voting process */ -public class VoterCancelException extends Exception{ +public class VoterCancelException extends Exception { // } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 173fa82..b389884 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,16 +1,19 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.List; import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the race-voting request to the UI. + * Upon receiving the answers for the race questions, the callback registers a new command to process + * the voter's answers (encrypt and then commit) into the controller's queue. + * If voter cancelled during the process, a cancelling exception is thrown and a RestartVotingCommand is + * registered through the onFailure() method + */ public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); protected final UIElement unsuccessfulVotingMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index 2634e27..f3f0308 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,13 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This callback is attached to requests to UI which ask the voter to wait for some process to finish. + * It actually asks nothing in the UI, and it is simply attached to the UI request as a place-holder. + * Therefore its onSuccess() method is empty + */ public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); protected final UIElement somethingWrongMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java index d2c99f2..fa7fc4a 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to audit the ballot */ public class AuditCommand extends ControllerCommand { public AuditCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java index 0621efb..c4e96bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to cast the ballot */ public class CastCommand extends ControllerCommand { public CastCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java index f555e4b..9d86edb 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to initiate the channel choice flow at the beginning of the voting */ public class ChannelChoiceCommand extends ControllerCommand { public ChannelChoiceCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java index 47d6f8b..c9b7023 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import java.util.List; /** - * Created by hai on 11/04/16. + * This command is registered in the controller right after the voter answered all the channel choice questions */ public class ChannelDeterminedCommand extends ControllerCommand { public List channelChoiceAnswers; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java index 76b0e77..0cdbacc 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to initiate asking the voter how to finalize (cast-or-audit) the ballot */ public class ChooseFinalizeOptionCommand extends ControllerCommand { public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java index 5bfc5c2..7743723 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java @@ -1,5 +1,9 @@ package meerkat.voting.controller.commands; +/** + * This is the base class for the controller commands. + * These commands are registered in a command queue of the controller. + */ public abstract class ControllerCommand { protected final int requestIdentifier; protected final long ballotSerialNumber; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index d7e4508..3917a31 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -3,6 +3,10 @@ package meerkat.voting.controller.commands; import meerkat.protobuf.Voting.BallotAnswer; import java.util.List; +/** + * a command registered after voter answered all ballot questions. + * The controller then initiates an encryption-signature-commit flow + */ public class EncryptAndCommitBallotCommand extends ControllerCommand { private final List votingAnswers; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java index b4a1fe7..fe3e369 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java @@ -2,6 +2,10 @@ package meerkat.voting.controller.commands; import meerkat.protobuf.Voting.*; +/** + * This command is not a part of the normal flow of the controller. + * It asks the controller to handle (report to voter) some error message + */ public class ReportErrorCommand extends ControllerCommand { private final UIElement errorMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java index 57906d2..600a163 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java @@ -1,6 +1,9 @@ package meerkat.voting.controller.commands; +/** + * a command to restart a voting flow (for a new voter) + */ public class RestartVotingCommand extends ControllerCommand { public RestartVotingCommand(int requestIdentifier, long ballotSerialNumber) { super(requestIdentifier, ballotSerialNumber); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java index 66dc992..b79a55f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java @@ -1,5 +1,10 @@ package meerkat.voting.controller.commands; +/** + * This is quite a special command not part of the normal voting flow. + * It extends the base EncryptAndCommitBallotCommand for occasions where first attempt of encryption failed + * and the voter asks to re-try encrypting and committing. + */ public class RetryEncryptAndCommitBallotCommand extends EncryptAndCommitBallotCommand { public RetryEncryptAndCommitBallotCommand(int requestIdentifier, diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index e9decae..6603b62 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -4,12 +4,26 @@ import meerkat.protobuf.Voting.*; import java.util.List; /** - * Created by hai on 02/05/16. + * An interface for the question-selection component. + * This component handles the connection between the channel choice questions and the race questions. + * It gets the answers for the channel choice questions and determines which race question to put in the voter's ballot. + * It also creates an identifier for this chosen channel. This identifier should appear in the plaintext of the ballot. + * The channel identifier does not identify a specific voter, but rather it identifies a specific voting channel */ public interface QuestionSelector { + /** + * determines an identifier for the channel of the voter + * @param channelChoiceAnswers The answers given by the voter to the channel choice questions + * @return an identifier of the channel. To be used by selectQuestionsForVoter(). This identifier should also appear on the plaintext of the ballot + */ public byte[] getChannelIdentifier (List channelChoiceAnswers); + /** + * determines which race questions to present to the voter according to its channel + * @param channelIdentifier the identifier of this specific channel + * @return the race questions (to present to the voter) + */ public List selectQuestionsForVoter (byte[] channelIdentifier); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 6181f05..7f2af87 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -11,28 +11,47 @@ import java.lang.Math; /** * A simple implementation of a QuestionSelector. * This implementation simply regards every single answer in the channel choice phase as an identifier of a category - * Every category is an array of ballot questions. + * Every category is an array of ballot race questions. * Data of categories is initialized and stored by a SimpleCategoriesSelectionData protobuf. * After receiving the answers from a channel choice phase, this class simply gathers all the categories * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question - * is included if its index appears in any chosen category, or in the default category shared by all voters) + * is included in the ballot if its index appears in any chosen category, or in the default category shared by all voters) */ public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + // all the possible race questions private final BallotQuestion[] allBallotQuestions; + + // this category is presented to any voter (regardless of his answers to the channel choice questions) private final int[] sharedDefaults; + + // all the categories. + // first index is the channel choice question number + // second index is a possible answer to this question + // categoryChoosers[questionNumber][answerNumber] is an array of indices (to the ballotQuestions array). + // This category of questions is included in the ballot if voter answered this specific answer to this channel choice question private final int[][][] categoryChoosers; + private final static byte QUESTION_SELECTED = (byte)1; private final static byte QUESTION_NOT_SELECTED = (byte)0; - + /** + * A very straight-forward constructor for the SimpleListCategoriesSelector + * @param allBallotQuestions all possible race questions for this election + * @param data a protobuf containing all the index categories + */ public SimpleListCategoriesSelector(List allBallotQuestions, SimpleCategoriesSelectionData data) { + // copies the ballot race question list into a member array this.allBallotQuestions = new BallotQuestion[allBallotQuestions.size()]; allBallotQuestions.toArray(this.allBallotQuestions); + + // copies the shared category list (as appears in the protobuf data) into a member array sharedDefaults = listToIntArray(data.getSharedDefaults().getQuestionIndexList()); + + // copies the category lists (as appear in the protobuf data) into a 3-dimensional member array int[][][] selectionDataTmp = new int[data.getCategoryChooserList().size()][][]; int channelChoiceQuestionNumber = 0; for (CategoryChooser catChooser: data.getCategoryChooserList()) { @@ -45,12 +64,21 @@ public class SimpleListCategoriesSelector implements QuestionSelector { ++channelChoiceQuestionNumber; } categoryChoosers = selectionDataTmp; + + // verifies in advance that there are not very suspicious indices in the selection data assertDataValid(); } + /* + * asserts that the selection data does not contain a question index which is beyond the length of + * the ballot race questions array. Otherwise, throws an IndexOutOfBoundsException + */ private void assertDataValid () { - int questionsLength = allBallotQuestions.length; + // find the maximum question index in the selection data int maxQuestionIndex = -1; + for (int index: sharedDefaults) { + maxQuestionIndex = Math.max(maxQuestionIndex, index); + } for (int[][] categoryChooser: categoryChoosers) { for (int[] category: categoryChooser) { for (int index: category) { @@ -58,6 +86,9 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } } } + + // asserts that the maximal question index in the selection data does not overflow the ballot race questions array + int questionsLength = allBallotQuestions.length; if (maxQuestionIndex >= questionsLength) { String errorMessage = "Selection data refers to question index " + maxQuestionIndex + " while we have only " + questionsLength + " questions totally"; logger.error(errorMessage); @@ -66,8 +97,21 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } + /** + * an implementation of the QuestionSelector interface method. + * In this selector class the identifier simply marks all the ballot race questions which appear in at least one + * category of the categories chosen by the voter (or in the shared defaults category) in the channel choice round. + * @param channelChoiceAnswers The answers given by the voter to the channel choice questions + * @return the channel identifier + */ @Override public byte[] getChannelIdentifier(List channelChoiceAnswers) { + /* + * Currently, this implementation of the QuestionSelector interface returns an over-simplified identifier which + * is merely an array of booleans (which flags the questions to appear in the ballot) + * For elections with more than one possible channel we should return a more printable and recognizable + * identifier to be put in the plaintext of the ballot + */ byte[] isSelected = new byte[allBallotQuestions.length]; java.util.Arrays.fill(isSelected, QUESTION_NOT_SELECTED); @@ -86,6 +130,10 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return isSelected; } + /* + * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). + * Otherwise, throws an exception. + */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { if (ballotAnswer.getAnswerCount() != 1) { String errorMessage = "SimpleListCategoriesSelector expects a single answer for every channel choice question\n"; @@ -109,6 +157,9 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return selectedQuestions; } + /* + * copies a List of Integers into an int[] array of same length + */ private int[] listToIntArray(List l) { int[] res = new int[l.size()]; int index = 0; From 06d69554d9d15317a26889e405e290b4ef6681f6 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 26 Jun 2016 17:07:03 +0300 Subject: [PATCH 36/66] fixed some merge conflicts which appeared for some unknown reason --- bulletin-board-server/build.gradle | 525 ++++++++++++++--------------- voting-booth/build.gradle | 384 +++++++++++---------- 2 files changed, 453 insertions(+), 456 deletions(-) diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 46ef4cf..766ed56 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -1,263 +1,262 @@ - -plugins { - id "us.kirchmeier.capsule" version "1.0.1" - id 'com.google.protobuf' version '0.7.0' - id 'org.akhikhl.gretty' version "1.2.4" -} - -apply plugin: 'org.akhikhl.gretty' -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' - -//apply plugin: 'application' - -//apply plugin: 'jetty' -//mainClassName = 'SQLiteIntegrationTest' - -apply plugin: 'maven-publish' - -// Is this a snapshot version? -ext { isSnapshot = false } - -ext { - groupId = 'org.factcenter.meerkat' - nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/" - - // Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing) - // Should be set in ${HOME}/.gradle/gradle.properties - nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : "" - nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" -} - -description = "Bulletin-board server web application" - -// Your project version -version = "0.0.1" - -version += "${isSnapshot ? '-SNAPSHOT' : ''}" - - -dependencies { - // Meerkat common - compile project(':meerkat-common') - compile project(':restful-api-common') - - // Jersey for RESTful API - compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' - - // JDBC connections - compile 'org.springframework:spring-jdbc:4.2.+' - compile 'org.xerial:sqlite-jdbc:3.8.+' - compile 'mysql:mysql-connector-java:5.1.+' - compile 'com.h2database:h2:1.0.+' - compile 'org.apache.commons:commons-dbcp2:2.0.+' - - // Servlets - compile 'javax.servlet:javax.servlet-api:3.0.+' - - // Logging - compile 'org.slf4j:slf4j-api:1.7.7' - runtime 'ch.qos.logback:logback-classic:1.1.2' - runtime 'ch.qos.logback:logback-core:1.1.2' - - // Google protobufs - compile 'com.google.protobuf:protobuf-java:3.+' - - // Depend on test resources from meerkat-common - testCompile project(path: ':meerkat-common', configuration: 'testOutput') - - testCompile 'junit:junit:4.+' - - runtime 'org.codehaus.groovy:groovy:2.4.+' -} - - -test { - exclude '**/*SQLite*Test*' - exclude '**/*H2*Test*' - exclude '**/*MySQL*Test*' - exclude '**/*IntegrationTest*' -} - -task myTest(type: Test) { - include '**/*MySQL*Test*' - outputs.upToDateWhen { false } -} - -task h2Test(type: Test) { - include '**/*H2*Test*' - outputs.upToDateWhen { false } -} - -task liteTest(type: Test) { - include '**/*SQLite*Test*' - outputs.upToDateWhen { false } -} - -task dbTest(type: Test) { - include '**/*H2*Test*' - include '**/*MySQL*Test*' - include '**/*SQLite*Test*' - outputs.upToDateWhen { false } -} - -task manualIntegration(type: Test) { - include '**/*IntegrationTest*' -} - -task integrationTest(type: Test) { - include '**/*IntegrationTest*' -// debug = true - outputs.upToDateWhen { false } - -} - -gretty { - httpPort = 8081 - contextPath = '/' - integrationTestTask = 'integrationTest' - loggingLevel = 'TRACE' - debugPort = 5006 -} - - - -/*==== You probably don't have to edit below this line =======*/ - -protobuf { - // Configure the protoc executable - protoc { - // Download from repositories - artifact = 'com.google.protobuf:protoc:3.+' - } -} - - -idea { - module { - project.sourceSets.each { sourceSet -> - - def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - - // add protobuf generated sources to generated source dir. - if ("test".equals(sourceSet.name)) { - testSourceDirs += file(srcDir) - } else { - sourceDirs += file(srcDir) - } - generatedSourceDirs += file(srcDir) - - } - - // Don't exclude build directory - excludeDirs -= file(buildDir) - } -} - - -/*=================================== - * "Fat" Build targets - *===================================*/ - -if (project.hasProperty('mainClassName') && (mainClassName != null)) { - - task mavenCapsule(type: MavenCapsule) { - description = "Generate a capsule jar that automatically downloads and caches dependencies when run." - applicationClass mainClassName - destinationDir = buildDir - } - - task fatCapsule(type: FatCapsule) { - description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class" - - destinationDir = buildDir - - def fatMain = hasProperty('fatmain') ? fatmain : mainClassName - - applicationClass fatMain - - def testJar = hasProperty('test') - - if (hasProperty('fatmain')) { - appendix = "fat-${fatMain}" - } else { - appendix = "fat" - } - - if (testJar) { - from sourceSets.test.output - } - } -} - -/*=================================== - * Repositories - *===================================*/ - -repositories { - - // Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral) - maven { - url nexusRepository - - if (isSnapshot) { - credentials { username - password - - username nexusUser - password nexusPassword - } - } - } - - // Use local maven repository - mavenLocal() - - jcenter() - - // Use 'maven central' for other dependencies. - mavenCentral() -} - -task "info" << { - println "Project: ${project.name}" -println "Description: ${project.description}" - println "--------------------------" - println "GroupId: $groupId" - println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})" - println "" -} -info.description 'Print some information about project parameters' - - -/*=================================== - * Publishing - *===================================*/ - -publishing { - publications { - mavenJava(MavenPublication) { - groupId project.groupId - pom.withXml { - asNode().appendNode('description', project.description) - } - from project.components.java - - } - } - repositories { - maven { - url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}" - credentials { username - password - - username nexusUser - password nexusPassword - } - } - } -} - - - + +plugins { + id "us.kirchmeier.capsule" version "1.0.1" + id 'com.google.protobuf' version '0.7.0' + id 'org.akhikhl.gretty' version "1.2.4" +} + +apply plugin: 'org.akhikhl.gretty' +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'idea' + +//apply plugin: 'application' + +//apply plugin: 'jetty' +//mainClassName = 'SQLiteIntegrationTest' + +apply plugin: 'maven-publish' + +// Is this a snapshot version? +ext { isSnapshot = false } + +ext { + groupId = 'org.factcenter.meerkat' + nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/" + + // Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing) + // Should be set in ${HOME}/.gradle/gradle.properties + nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : "" + nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" +} + +description = "Bulletin-board server web application" + +// Your project version +version = "0.0.1" + +version += "${isSnapshot ? '-SNAPSHOT' : ''}" + + +dependencies { + // Meerkat common + compile project(':meerkat-common') + compile project(':restful-api-common') + + // Jersey for RESTful API + compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' + + // JDBC connections + compile 'org.springframework:spring-jdbc:4.2.+' + compile 'org.xerial:sqlite-jdbc:3.8.+' + compile 'mysql:mysql-connector-java:5.1.+' + compile 'com.h2database:h2:1.0.+' + compile 'org.apache.commons:commons-dbcp2:2.0.+' + + // Servlets + compile 'javax.servlet:javax.servlet-api:3.0.+' + + // Logging + compile 'org.slf4j:slf4j-api:1.7.7' + runtime 'ch.qos.logback:logback-classic:1.1.2' + runtime 'ch.qos.logback:logback-core:1.1.2' + + // Google protobufs + compile 'com.google.protobuf:protobuf-java:3.+' + + // Depend on test resources from meerkat-common + testCompile project(path: ':meerkat-common', configuration: 'testOutput') + + testCompile 'junit:junit:4.+' + + runtime 'org.codehaus.groovy:groovy:2.4.+' +} + + +test { + exclude '**/*SQLite*Test*' + exclude '**/*H2*Test*' + exclude '**/*MySQL*Test*' + exclude '**/*IntegrationTest*' +} + +task myTest(type: Test) { + include '**/*MySQL*Test*' + outputs.upToDateWhen { false } +} + +task h2Test(type: Test) { + include '**/*H2*Test*' + outputs.upToDateWhen { false } +} + +task liteTest(type: Test) { + include '**/*SQLite*Test*' + outputs.upToDateWhen { false } +} + +task dbTest(type: Test) { + include '**/*H2*Test*' + include '**/*MySQL*Test*' + include '**/*SQLite*Test*' + outputs.upToDateWhen { false } +} + +task manualIntegration(type: Test) { + include '**/*IntegrationTest*' +} + +task integrationTest(type: Test) { + include '**/*IntegrationTest*' +// debug = true + outputs.upToDateWhen { false } + +} + +gretty { + httpPort = 8081 + contextPath = '/' + integrationTestTask = 'integrationTest' + loggingLevel = 'TRACE' + debugPort = 5006 +} + + + +/*==== You probably don't have to edit below this line =======*/ + +protobuf { + // Configure the protoc executable + protoc { + // Download from repositories + artifact = 'com.google.protobuf:protoc:3.+' + } +} + + +idea { + module { + project.sourceSets.each { sourceSet -> + + def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" + + // add protobuf generated sources to generated source dir. + if ("test".equals(sourceSet.name)) { + testSourceDirs += file(srcDir) + } else { + sourceDirs += file(srcDir) + } + generatedSourceDirs += file(srcDir) + + } + + // Don't exclude build directory + excludeDirs -= file(buildDir) + } +} + + +/*=================================== + * "Fat" Build targets + *===================================*/ + +if (project.hasProperty('mainClassName') && (mainClassName != null)) { + + task mavenCapsule(type: MavenCapsule) { + description = "Generate a capsule jar that automatically downloads and caches dependencies when run." + applicationClass mainClassName + destinationDir = buildDir + } + + task fatCapsule(type: FatCapsule) { + description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class" + + destinationDir = buildDir + + def fatMain = hasProperty('fatmain') ? fatmain : mainClassName + + applicationClass fatMain + + def testJar = hasProperty('test') + + if (hasProperty('fatmain')) { + appendix = "fat-${fatMain}" + } else { + appendix = "fat" + } + + if (testJar) { + from sourceSets.test.output + } + } +} + +/*=================================== + * Repositories + *===================================*/ + +repositories { + + // Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral) + maven { + url nexusRepository + + if (isSnapshot) { + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } + + // Use local maven repository + mavenLocal() + + jcenter() + + // Use 'maven central' for other dependencies. + mavenCentral() +} + +task "info" << { + println "Project: ${project.name}" +println "Description: ${project.description}" + println "--------------------------" + println "GroupId: $groupId" + println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})" + println "" +} +info.description 'Print some information about project parameters' + + +/*=================================== + * Publishing + *===================================*/ + +publishing { + publications { + mavenJava(MavenPublication) { + groupId project.groupId + pom.withXml { + asNode().appendNode('description', project.description) + } + from project.components.java + + } + } + repositories { + maven { + url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}" + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } +} + + diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 241e3c3..7619b48 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -1,193 +1,191 @@ - -plugins { - id "us.kirchmeier.capsule" version "1.0.1" - id 'com.google.protobuf' version '0.7.0' -} - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' - -apply plugin: 'maven-publish' - -// Uncomment the lines below to define an application -// (this will also allow you to build a "fatCapsule" which includes -// the entire application, including all dependencies in a single jar) -//apply plugin: 'application' -//mainClassName='your.main.ApplicationClass' - -// Is this a snapshot version? -ext { isSnapshot = false } - -ext { - groupId = 'org.factcenter.meerkat' - nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/" - - // Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing) - // Should be set in ${HOME}/.gradle/gradle.properties - nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : "" - nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" -} - -description = "Meerkat voting booth application" - -// Your project version -version = "0.0" - -version += "${isSnapshot ? '-SNAPSHOT' : ''}" - - -dependencies { - // Meerkat common - compile project(':meerkat-common') - - // Logging - compile 'org.slf4j:slf4j-api:1.7.7' - runtime 'ch.qos.logback:logback-classic:1.1.2' - runtime 'ch.qos.logback:logback-core:1.1.2' - - // Google protobufs - compile 'com.google.protobuf:protobuf-java:3.+' - - testCompile 'junit:junit:4.+' - - runtime 'org.codehaus.groovy:groovy:2.4.+' -} - - -/*==== You probably don't have to edit below this line =======*/ - -protobuf { - // Configure the protoc executable - protoc { - // Download from repositories - artifact = 'com.google.protobuf:protoc:3.+' - } -} - - -idea { - module { - project.sourceSets.each { sourceSet -> - - def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - - // add protobuf generated sources to generated source dir. - if ("test".equals(sourceSet.name)) { - testSourceDirs += file(srcDir) - } else { - sourceDirs += file(srcDir) - } - generatedSourceDirs += file(srcDir) - - } - - // Don't exclude build directory - excludeDirs -= file(buildDir) - } -} - - -/*=================================== - * "Fat" Build targets - *===================================*/ - -if (project.hasProperty('mainClassName') && (mainClassName != null)) { - - task mavenCapsule(type: MavenCapsule) { - description = "Generate a capsule jar that automatically downloads and caches dependencies when run." - applicationClass mainClassName - destinationDir = buildDir - } - - task fatCapsule(type: FatCapsule) { - description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class" - - destinationDir = buildDir - - def fatMain = hasProperty('fatmain') ? fatmain : mainClassName - - applicationClass fatMain - - def testJar = hasProperty('test') - - if (hasProperty('fatmain')) { - appendix = "fat-${fatMain}" - } else { - appendix = "fat" - } - - if (testJar) { - from sourceSets.test.output - } - } -} - -/*=================================== - * Repositories - *===================================*/ - -repositories { - - // Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral) - maven { - url nexusRepository - - if (isSnapshot) { - credentials { username - password - - username nexusUser - password nexusPassword - } - } - } - - // Use local maven repository - mavenLocal() - - // Use 'maven central' for other dependencies. - mavenCentral() -} - -task "info" << { - println "Project: ${project.name}" -println "Description: ${project.description}" - println "--------------------------" - println "GroupId: $groupId" - println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})" - println "" -} -info.description 'Print some information about project parameters' - - -/*=================================== - * Publishing - *===================================*/ - -publishing { - publications { - mavenJava(MavenPublication) { - groupId project.groupId - pom.withXml { - asNode().appendNode('description', project.description) - } - from project.components.java - - } - } - repositories { - maven { - url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}" - credentials { username - password - - username nexusUser - password nexusPassword - } - } - } -} - - - + +plugins { + id "us.kirchmeier.capsule" version "1.0.1" + id 'com.google.protobuf' version '0.7.0' +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'idea' + +apply plugin: 'maven-publish' + +// Uncomment the lines below to define an application +// (this will also allow you to build a "fatCapsule" which includes +// the entire application, including all dependencies in a single jar) +//apply plugin: 'application' +//mainClassName='your.main.ApplicationClass' + +// Is this a snapshot version? +ext { isSnapshot = false } + +ext { + groupId = 'org.factcenter.meerkat' + nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/" + + // Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing) + // Should be set in ${HOME}/.gradle/gradle.properties + nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : "" + nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" +} + +description = "Meerkat voting booth application" + +// Your project version +version = "0.0" + +version += "${isSnapshot ? '-SNAPSHOT' : ''}" + + +dependencies { + // Meerkat common + compile project(':meerkat-common') + + // Logging + compile 'org.slf4j:slf4j-api:1.7.7' + runtime 'ch.qos.logback:logback-classic:1.1.2' + runtime 'ch.qos.logback:logback-core:1.1.2' + + // Google protobufs + compile 'com.google.protobuf:protobuf-java:3.+' + + testCompile 'junit:junit:4.+' + + runtime 'org.codehaus.groovy:groovy:2.4.+' +} + + +/*==== You probably don't have to edit below this line =======*/ + +protobuf { + // Configure the protoc executable + protoc { + // Download from repositories + artifact = 'com.google.protobuf:protoc:3.+' + } +} + + +idea { + module { + project.sourceSets.each { sourceSet -> + + def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" + + // add protobuf generated sources to generated source dir. + if ("test".equals(sourceSet.name)) { + testSourceDirs += file(srcDir) + } else { + sourceDirs += file(srcDir) + } + generatedSourceDirs += file(srcDir) + + } + + // Don't exclude build directory + excludeDirs -= file(buildDir) + } +} + + +/*=================================== + * "Fat" Build targets + *===================================*/ + +if (project.hasProperty('mainClassName') && (mainClassName != null)) { + + task mavenCapsule(type: MavenCapsule) { + description = "Generate a capsule jar that automatically downloads and caches dependencies when run." + applicationClass mainClassName + destinationDir = buildDir + } + + task fatCapsule(type: FatCapsule) { + description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class" + + destinationDir = buildDir + + def fatMain = hasProperty('fatmain') ? fatmain : mainClassName + + applicationClass fatMain + + def testJar = hasProperty('test') + + if (hasProperty('fatmain')) { + appendix = "fat-${fatMain}" + } else { + appendix = "fat" + } + + if (testJar) { + from sourceSets.test.output + } + } +} + +/*=================================== + * Repositories + *===================================*/ + +repositories { + + // Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral) + maven { + url nexusRepository + + if (isSnapshot) { + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } + + // Use local maven repository + mavenLocal() + + // Use 'maven central' for other dependencies. + mavenCentral() +} + +task "info" << { + println "Project: ${project.name}" +println "Description: ${project.description}" + println "--------------------------" + println "GroupId: $groupId" + println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})" + println "" +} +info.description 'Print some information about project parameters' + + +/*=================================== + * Publishing + *===================================*/ + +publishing { + publications { + mavenJava(MavenPublication) { + groupId project.groupId + pom.withXml { + asNode().appendNode('description', project.description) + } + from project.components.java + + } + } + repositories { + maven { + url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}" + credentials { username + password + + username nexusUser + password nexusPassword + } + } + } +} + From 437992144565027adb04c8185fcc264bad88cc17 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:26:00 +0300 Subject: [PATCH 37/66] For some reason restful API did not appear in my gradle.build. It is fixed now. --- voting-booth/build.gradle | 1 + ...ception.java => VoterCancelThrowable.java} | 2 +- .../output/AsyncRunnableOutputDevice.java | 161 ++++++++++++++++++ .../voting/output/NetworkVirtualPrinter.java | 37 ++++ 4 files changed, 200 insertions(+), 1 deletion(-) rename voting-booth/src/main/java/meerkat/voting/controller/callbacks/{VoterCancelException.java => VoterCancelThrowable.java} (76%) create mode 100644 voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 7619b48..ef89f86 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -40,6 +40,7 @@ version += "${isSnapshot ? '-SNAPSHOT' : ''}" dependencies { // Meerkat common compile project(':meerkat-common') + compile project(':restful-api-common') // Logging compile 'org.slf4j:slf4j-api:1.7.7' diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java similarity index 76% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java index 2844fc1..38c2c8b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java @@ -3,6 +3,6 @@ package meerkat.voting.controller.callbacks; /** * Just a simple unique exception to throw when a voter aborts/cancels the voting during the voting process */ -public class VoterCancelException extends Exception { +public class VoterCancelThrowable extends Throwable { // } diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java new file mode 100644 index 0000000..50bd6d5 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -0,0 +1,161 @@ +package meerkat.voting.output; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.BoolValue; +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.protobuf.Voting.*; +import meerkat.rest.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.*; +import javax.ws.rs.core.Response; + +import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { + + private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; + + private SignedEncryptedBallot signedEncryptedBallot; + + private final WebTarget successfulPrintTarget; + + public AsyncRunnableOutputDevice(String address) { + logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); + logger.info("A NetworkVirtualPrinter is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; + + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + } + + @Override + public void run () { + logger.info("starts running"); + while (! wasShutDownCalled()) { + try { + OutputCommand command = queue.take(); + handleSingleCommand(command); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from command queue " + e); + } + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + + + private void handleSingleCommand(OutputCommand command) { + if (command instanceof CommitOutputCommand) { + doCommitToBallot((CommitOutputCommand)command); + } + else if (command instanceof AuditOutputCommand) { + doAudit((AuditOutputCommand)command); + } + else if (command instanceof CastOutputCommand) { + doCastBallot((CastOutputCommand)command); + } + else if (command instanceof CancelOutputCommand) { + doCancel((CancelOutputCommand)command); + } + else { + String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + + @Override + public void commitToBallot(PlaintextBallot plaintextBallot, + SignedEncryptedBallot signedEncryptedBallot, + FutureCallback callback) { + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + @Override + public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); + } + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + signedEncryptedBallot = command.getSignedEncryptedBallot(); + command.getCallback().onSuccess(null); + } + + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + + + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setSignedEncryptedBallot(this.signedEncryptedBallot) + .build(); + + Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + BoolValue b = response.readEntity(BoolValue.class); + response.close(); + + if (b.getValue()) { + command.getCallback().onSuccess(null); + } + else { + command.getCallback().onFailure(new IOException()); + } + } + + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java new file mode 100644 index 0000000..d3e3625 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -0,0 +1,37 @@ +package meerkat.voting.output; + +import com.google.protobuf.BoolValue; +import meerkat.pollingstation.PollingStationScanner; +import meerkat.protobuf.PollingStation.*; +import meerkat.rest.*; + +import javax.ws.rs.client.*; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class NetworkVirtualPrinter implements PollingStationScanner.Producer { + + WebTarget successfulScanPath; + WebTarget errorPath; + + public NetworkVirtualPrinter(String address) { + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulScanPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + errorPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + } + + @Override + public BoolValue newScan(ScannedData scannedData) { + return null; + } + + @Override + public BoolValue reportScanError(ErrorMsg errorMsg) { + return null; + } +} From 438df78e368a308e8ab1167764509d9180f2724c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:26:50 +0300 Subject: [PATCH 38/66] Changed the ToySignature test file to match the new Signature interface. --- .../src/main/java/meerkat/voting/ToySignature.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/ToySignature.java b/voting-booth/src/main/java/meerkat/voting/ToySignature.java index e2473c9..8b24a3c 100644 --- a/voting-booth/src/main/java/meerkat/voting/ToySignature.java +++ b/voting-booth/src/main/java/meerkat/voting/ToySignature.java @@ -4,13 +4,11 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.crypto.DigitalSignature; import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Crypto.Signature; import java.io.IOException; import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; +import java.security.*; import java.security.cert.CertificateException; /** @@ -69,6 +67,11 @@ public class ToySignature implements DigitalSignature { throw new UnsupportedOperationException(); } + @Override + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { + throw new UnsupportedOperationException(); + } + @Override public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { throw new UnsupportedOperationException(); From 3a5908ac49976634fa3c786f33300500accadc15 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:28:14 +0300 Subject: [PATCH 39/66] A cancel by the voter is now sent to the execution flow as a Throwable rather than an Exception. --- .../controller/callbacks/ChannelChoiceCallback.java | 4 ++-- .../voting/controller/callbacks/VotingCallback.java | 2 +- .../src/main/java/meerkat/voting/ui/SystemConsoleUI.java | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index a87fe0a..7b97a82 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -35,8 +35,8 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onFailure(Throwable t) { - if (t instanceof VoterCancelException) { - // voter has cancelled during the UI channel choice process. A VoterCancelException is thrown + if (t instanceof VoterCancelThrowable) { + // voter has cancelled during the UI channel choice process. A VoterCancelThrowable is thrown logger.debug("ChannelChoiceCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index b389884..96c940b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -34,7 +34,7 @@ public class VotingCallback extends ControllerCallback> { @Override public void onFailure(Throwable t) { - if (t instanceof VoterCancelException) { + if (t instanceof VoterCancelThrowable) { logger.debug("VotingCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index bc3ac92..b8a3828 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -155,7 +155,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } - catch (VoterCancelException e) { + catch (VoterCancelThrowable e) { command.getCallback().onFailure(e); } catch (IOException e) { @@ -179,7 +179,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } - catch (VoterCancelException e) { + catch (VoterCancelThrowable e) { command.getCallback().onFailure(e); } catch (IOException e) { @@ -339,7 +339,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private List askVoterForAnswers(List questions) throws VoterCancelException, IOException { + private List askVoterForAnswers(List questions) throws VoterCancelThrowable, IOException { assertQuestionsAreValid (questions); @@ -354,7 +354,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { String s = readInputLine(); if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { - throw new VoterCancelException(); + throw new VoterCancelThrowable(); } else if (s.equals("back") || s.equals("b")) { --index; From 14fac728b3e816500e5b45e11a02ebcac56e0f66 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:32:00 +0300 Subject: [PATCH 40/66] 1. ScannedData now has a Channel and a SignedEncryptedBallot attributes, rather than just 'data' attribute 2. Implemented a NetworkVirtualPrinter output device, and now both this class and the previous SystemConsoleOutputDevice extend the same new abstract class AsyncRunnableOutputDevice which supplies default implementations for the interface methods. --- .../main/proto/meerkat/PollingStation.proto | 7 +- .../PollingStationWebScannerTest.java | 6 +- .../output/AsyncRunnableOutputDevice.java | 77 +++------------ .../voting/output/NetworkVirtualPrinter.java | 79 ++++++++++++--- .../output/SystemConsoleOutputDevice.java | 98 ++----------------- 5 files changed, 98 insertions(+), 169 deletions(-) diff --git a/meerkat-common/src/main/proto/meerkat/PollingStation.proto b/meerkat-common/src/main/proto/meerkat/PollingStation.proto index 0cdc658..09596a5 100644 --- a/meerkat-common/src/main/proto/meerkat/PollingStation.proto +++ b/meerkat-common/src/main/proto/meerkat/PollingStation.proto @@ -2,11 +2,16 @@ syntax = "proto3"; package meerkat; +import "meerkat/voting.proto"; + option java_package = "meerkat.protobuf"; // Container for scanned data message ScannedData { - bytes data = 1; + bytes channel = 1; + + SignedEncryptedBallot signed_encrypted_ballot = 2; + } // Container for error messages diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index 7da106c..e94c633 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -2,7 +2,9 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.PollingStation.*; +import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; import meerkat.rest.*; @@ -46,7 +48,7 @@ public class PollingStationWebScannerTest { @Override public void onSuccess(ScannedData result) { - dataIsAsExpected = result.getData().equals(expectedData.getData()); + dataIsAsExpected = result.getChannel().equals(expectedData.getChannel()); semaphore.release(); } @@ -109,7 +111,7 @@ public class PollingStationWebScannerTest { byte[] data = {(byte) 1, (byte) 2}; ScannedData scannedData = ScannedData.newBuilder() - .setData(ByteString.copyFrom(data)) + .setChannel(ByteString.copyFrom(data)) .build(); scanner.subscribe(new ScanHandler(scannedData)); diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 50bd6d5..d4620bb 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -1,46 +1,30 @@ package meerkat.voting.output; import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.BoolValue; -import meerkat.protobuf.PollingStation.ScannedData; -import meerkat.protobuf.Voting.*; -import meerkat.rest.*; +import meerkat.protobuf.Voting.BallotSecrets; +import meerkat.protobuf.Voting.PlaintextBallot; +import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.voting.controller.callbacks.ControllerCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.*; -import javax.ws.rs.core.Response; - -import java.io.IOException; import java.util.concurrent.LinkedBlockingQueue; -import static meerkat.pollingstation.PollingStationConstants.*; - /** * Created by hai on 27/06/16. */ -public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { +public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; private LinkedBlockingQueue queue; private volatile boolean shutDownHasBeenCalled; - private SignedEncryptedBallot signedEncryptedBallot; - - private final WebTarget successfulPrintTarget; - - public AsyncRunnableOutputDevice(String address) { + public AsyncRunnableOutputDevice() { logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); - logger.info("A NetworkVirtualPrinter is constructed"); + logger.info("AsyncRunnableOutputDevice is constructed"); queue = new LinkedBlockingQueue<>(); shutDownHasBeenCalled = false; - - Client client = ClientBuilder.newClient(); - client.register(ProtobufMessageBodyReader.class); - client.register(ProtobufMessageBodyWriter.class); - successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); } @Override @@ -69,6 +53,15 @@ public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable } + abstract void doCommitToBallot(CommitOutputCommand command); + + abstract void doAudit(AuditOutputCommand command); + + abstract void doCastBallot(CastOutputCommand command); + + abstract void doCancel(CancelOutputCommand command); + + private void handleSingleCommand(OutputCommand command) { if (command instanceof CommitOutputCommand) { doCommitToBallot((CommitOutputCommand)command); @@ -118,44 +111,4 @@ public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable } - public void doCommitToBallot(CommitOutputCommand command) { - logger.debug("entered method doCommitToBallot"); - signedEncryptedBallot = command.getSignedEncryptedBallot(); - command.getCallback().onSuccess(null); - } - - - public void doAudit(AuditOutputCommand command) { - logger.debug("entered method doAudit"); - signedEncryptedBallot = null; - command.getCallback().onSuccess(null); - } - - - public void doCastBallot(CastOutputCommand command) { - logger.debug("entered method doCastBallot"); - ScannedData scannedData = ScannedData.newBuilder() - .setChannel(null) //TODO: fill the details for the channel to be able to send here - .setSignedEncryptedBallot(this.signedEncryptedBallot) - .build(); - - Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); - BoolValue b = response.readEntity(BoolValue.class); - response.close(); - - if (b.getValue()) { - command.getCallback().onSuccess(null); - } - else { - command.getCallback().onFailure(new IOException()); - } - } - - - public void doCancel(CancelOutputCommand command) { - logger.debug("entered method doCancel"); - signedEncryptedBallot = null; - command.getCallback().onSuccess(null); - } - } diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index d3e3625..f65959f 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -1,37 +1,84 @@ package meerkat.voting.output; import com.google.protobuf.BoolValue; -import meerkat.pollingstation.PollingStationScanner; -import meerkat.protobuf.PollingStation.*; -import meerkat.rest.*; +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.protobuf.Voting.SignedEncryptedBallot; +import meerkat.rest.Constants; +import meerkat.rest.ProtobufMessageBodyReader; +import meerkat.rest.ProtobufMessageBodyWriter; +import meerkat.voting.output.outputcommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import javax.ws.rs.client.*; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import java.io.IOException; -import static meerkat.pollingstation.PollingStationConstants.*; +import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; /** * Created by hai on 27/06/16. */ -public class NetworkVirtualPrinter implements PollingStationScanner.Producer { +public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { - WebTarget successfulScanPath; - WebTarget errorPath; + private Logger logger; + private SignedEncryptedBallot signedEncryptedBallot; + private final WebTarget successfulPrintTarget; public NetworkVirtualPrinter(String address) { + super(); + + logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); + logger.info("A NetworkVirtualPrinter is constructed"); + Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); - successfulScanPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); - errorPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); } - @Override - public BoolValue newScan(ScannedData scannedData) { - return null; + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + signedEncryptedBallot = command.getSignedEncryptedBallot(); + command.getCallback().onSuccess(null); } - @Override - public BoolValue reportScanError(ErrorMsg errorMsg) { - return null; + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); } + + + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setSignedEncryptedBallot(this.signedEncryptedBallot) + .build(); + + Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + BoolValue b = response.readEntity(BoolValue.class); + response.close(); + + if (b.getValue()) { + command.getCallback().onSuccess(null); + } + else { + command.getCallback().onFailure(new IOException()); + } + } + + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 614dc40..62bebe3 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -1,96 +1,28 @@ package meerkat.voting.output; -import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.LinkedBlockingQueue; - /** * A toy OutputDevice class * outputs everything simply to the System console */ -public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { +public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { private Logger logger; - private LinkedBlockingQueue queue; - private volatile boolean shutDownHasBeenCalled; public SystemConsoleOutputDevice () { + super(); logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); - queue = new LinkedBlockingQueue<>(); - shutDownHasBeenCalled = false; } - /* - * Returns the UTF8 decoding of byte-string data - */ - private static String bytesToString(ByteString data) { - return data.toStringUtf8(); - } - @Override - public void run () { - logger.info("UI starts running"); - while (! wasShutDownCalled()) { - try { - OutputCommand command = queue.take(); - handleSingleCommand(command); - } - catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); - } - } - } - - private boolean wasShutDownCalled () { - return shutDownHasBeenCalled; - } - - @Override - public void callShutDown() { - logger.info("callShutDown command has been called"); - shutDownHasBeenCalled = true; - queue.clear(); - } - - - private void handleSingleCommand(OutputCommand command) { - if (command instanceof CommitOutputCommand) { - doCommitToBallot((CommitOutputCommand)command); - } - else if (command instanceof AuditOutputCommand) { - doAudit((AuditOutputCommand)command); - } - else if (command instanceof CastOutputCommand) { - doCastBallot((CastOutputCommand)command); - } - else if (command instanceof CancelOutputCommand) { - doCancel((CancelOutputCommand)command); - } - else { - String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + - command.getClass().getName(); - logger.error(errorMessage); - throw new RuntimeException(errorMessage); - } - } - - - @Override - public void commitToBallot(PlaintextBallot plaintextBallot, - SignedEncryptedBallot signedEncryptedBallot, - FutureCallback callback) { - logger.debug("Output interface call to commit to ballot"); - queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); - } public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); @@ -111,12 +43,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { - logger.debug("an interface call to audit"); - queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); - } - public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); System.out.println("Auditing"); @@ -127,12 +53,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void castBallot(FutureCallback callback) { - logger.debug("an interface call to cast ballot"); - queue.add(new CastOutputCommand((ControllerCallback)callback)); - } - public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); System.out.println("Ballot finalized for casting!"); @@ -140,12 +60,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void cancelBallot(FutureCallback callback) { - logger.debug("an interface call to cancel the output"); - queue.add(new CancelOutputCommand((ControllerCallback)callback)); - } - public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); System.out.println("Ballot cancelled!"); @@ -165,4 +79,12 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { System.out.println(bytesToString(data)); } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + } From e298ab1e760b1365f00a57bc01372cb135ab1985 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:35:36 +0300 Subject: [PATCH 41/66] removed two unnecessary imports --- .../meerkat/pollingstation/PollingStationWebScannerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index e94c633..6e88baa 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -2,9 +2,7 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; -import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.PollingStation.*; -import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; import meerkat.rest.*; From 66e5db9f227bb32062ad3ed11d889b5454648f18 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:51:49 +0300 Subject: [PATCH 42/66] cleared some unnecessary imports --- .../meerkat/voting/controller/VotingBoothController.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index e8eae93..6008d24 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -1,20 +1,17 @@ package meerkat.voting.controller; -import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.selector.QuestionSelector; import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.ui.VotingBoothUI; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import java.io.IOException; -import java.util.List; /** * An interface for the controller component of the voting booth */ -public interface VotingBoothController extends Runnable{ +public interface VotingBoothController extends Runnable { /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller From 7db62187353bff79fc7e5658c8602138772673ad Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:53:28 +0300 Subject: [PATCH 43/66] fixed: access to the static system messages from the StorageManage class, rather than its instance --- .../voting/controller/VotingBoothImpl.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 849651f..a71dadd 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,6 +1,5 @@ package meerkat.voting.controller; -import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; @@ -153,7 +152,7 @@ public class VotingBoothImpl implements VotingBoothController { } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); - doReportErrorAndForceRestart(systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE)); + doReportErrorAndForceRestart(systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -182,7 +181,7 @@ public class VotingBoothImpl implements VotingBoothController { queue.clear(); state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); ui.showErrorMessageWithButtons(errorMessage, - new UIElement[]{systemMessages.get(storageManager.RESTART_VOTING_BUTTON)}, + new UIElement[]{systemMessages.get(StorageManager.RESTART_VOTING_BUTTON)}, new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); @@ -196,7 +195,7 @@ public class VotingBoothImpl implements VotingBoothController { new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); + systemMessages.get(StorageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); } else { logger.debug("doChooseChannel: current state is " + state.stateIdentifier); @@ -215,7 +214,7 @@ public class VotingBoothImpl implements VotingBoothController { new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNSUCCESSFUL_VOTING_MESSAGE))); + systemMessages.get(StorageManager.UNSUCCESSFUL_VOTING_MESSAGE))); } else { logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); @@ -231,7 +230,7 @@ public class VotingBoothImpl implements VotingBoothController { ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); + systemMessages.get(StorageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); } else { logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); @@ -243,25 +242,25 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("doing commit"); try { setBallotData(task); - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_COMMIT_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_COMMIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.commitToBallot(state.plaintextBallot, state.signedEncryptedBallot, new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; } catch (SignatureException | IOException e) { logger.error("doCommit: encryption failed. exception: " + e); - UIElement errorMessage = systemMessages.get(storageManager.ENCRYPTION_FAILED_MESSAGE); + UIElement errorMessage = systemMessages.get(StorageManager.ENCRYPTION_FAILED_MESSAGE); UIElement[] buttons = new UIElement[]{ - systemMessages.get(storageManager.RETRY_BUTTON), - systemMessages.get(storageManager.CANCEL_VOTE_BUTTON)}; + systemMessages.get(StorageManager.RETRY_BUTTON), + systemMessages.get(StorageManager.CANCEL_VOTE_BUTTON)}; EncryptionFailedCallback callback = new EncryptionFailedCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -294,28 +293,28 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_AUDIT_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_AUDIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.audit(state.secrets, new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_CAST_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.castBallot( new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } } else { From 2b56928e9ace0f93dc4167d1adb15542656db6c3 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:54:36 +0300 Subject: [PATCH 44/66] added some JavaDoc comments and documentation --- .../SimpleListCategoriesSelector.java | 10 +++-- .../voting/encryptor/VBCryptoManager.java | 1 + .../voting/encryptor/VBCryptoManagerImpl.java | 4 +- .../output/AsyncRunnableOutputDevice.java | 42 ++++++++++++++----- .../voting/output/BallotOutputDevice.java | 5 ++- .../voting/output/NetworkVirtualPrinter.java | 23 +++++++--- .../output/SystemConsoleOutputDevice.java | 27 ++++++++---- .../outputcommands/AuditOutputCommand.java | 2 +- .../outputcommands/CancelOutputCommand.java | 2 +- .../outputcommands/CastOutputCommand.java | 2 +- .../outputcommands/CommitOutputCommand.java | 2 +- .../output/outputcommands/OutputCommand.java | 4 +- 12 files changed, 90 insertions(+), 34 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 7f2af87..b39fede 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -69,7 +69,7 @@ public class SimpleListCategoriesSelector implements QuestionSelector { assertDataValid(); } - /* + /** * asserts that the selection data does not contain a question index which is beyond the length of * the ballot race questions array. Otherwise, throws an IndexOutOfBoundsException */ @@ -130,9 +130,11 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return isSelected; } - /* + /** * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). * Otherwise, throws an exception. + * @param ballotAnswer + * @param questionNumber the number of the question (needed only for error message strings) */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { if (ballotAnswer.getAnswerCount() != 1) { @@ -157,8 +159,10 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return selectedQuestions; } - /* + /** * copies a List of Integers into an int[] array of same length + * @param l a list of Integers + * @return an array of ints */ private int[] listToIntArray(List l) { int[] res = new int[l.size()]; diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index d5216e4..04416f3 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -7,6 +7,7 @@ import java.security.SignatureException; /** * An interface for the encryptor component of the voting booth + * It handles both the encryption and the digital signature */ public interface VBCryptoManager { /** diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 2bc9729..83fb8b0 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -11,13 +11,13 @@ import java.security.SignatureException; import java.util.Random; /** - * Created by hai on 07/06/16. + * A basic implementation of the VBCryptoManager interface */ public class VBCryptoManagerImpl implements VBCryptoManager { protected final static Logger logger = LoggerFactory.getLogger(VBCryptoManagerImpl.class); - private final Random random; + private final Random random; //TODO: Random object should be more cryptographycally secure private final Encryption encryption; private final DigitalSignature digitalSignature; diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index d4620bb..88dde5b 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -12,7 +12,9 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 27/06/16. + * This is a base class for simple OutputDevices which run asynchronously (as a separate thread). + * The methods of the BallotOutputDevice simply register a matching OutputCommand in the instance's queue + * The Runnable.run method simply takes the next registered command and calls the matching (abstract) method */ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { @@ -52,16 +54,10 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R queue.clear(); } - - abstract void doCommitToBallot(CommitOutputCommand command); - - abstract void doAudit(AuditOutputCommand command); - - abstract void doCastBallot(CastOutputCommand command); - - abstract void doCancel(CancelOutputCommand command); - - + /** + * chooses the next method to run according to the type of the given OutputCommand + * @param command any valid OutputCommand + */ private void handleSingleCommand(OutputCommand command) { if (command instanceof CommitOutputCommand) { doCommitToBallot((CommitOutputCommand)command); @@ -111,4 +107,28 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R } + /** + * This method should be filled by an extending class. It should have the details of how to commit to a ballot + * @param command + */ + abstract void doCommitToBallot(CommitOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to audit the ballot + * @param command + */ + abstract void doAudit(AuditOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to cast the ballot + * @param command + */ + abstract void doCastBallot(CastOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to cancel the ballot output + * @param command + */ + abstract void doCancel(CancelOutputCommand command); + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 97fa7ed..3909ce3 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -20,7 +20,7 @@ public interface BallotOutputDevice { /** * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. - * @param ballotSecrets - the secrtes of the encryption + * @param ballotSecrets - the secrets of the encryption * @param callback - a callback object which expects no return value */ public void audit(BallotSecrets ballotSecrets, FutureCallback callback); @@ -37,5 +37,8 @@ public interface BallotOutputDevice { */ public void cancelBallot(FutureCallback callback); + /** + * A method for shutting down the Output Device + */ public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index f65959f..05be623 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -20,20 +20,17 @@ import java.io.IOException; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; /** - * Created by hai on 27/06/16. + * A ballot output device for the network. It simply sends details over the wire */ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); private SignedEncryptedBallot signedEncryptedBallot; private final WebTarget successfulPrintTarget; public NetworkVirtualPrinter(String address) { super(); - - logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); logger.info("A NetworkVirtualPrinter is constructed"); - Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); @@ -41,6 +38,12 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for committing. + * It simply keeps the ballot details for later. + * When the voter chooses to Cast the ballot, these details are sent over the wire. + * @param command a CommitOutputCommand with the signed encryption of the ballot + */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); signedEncryptedBallot = command.getSignedEncryptedBallot(); @@ -48,6 +51,9 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for auditing. + */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); signedEncryptedBallot = null; @@ -55,6 +61,10 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * This is where the magic happens. The signed encrypted ballot is transmitted over the wire + * @param command + */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); ScannedData scannedData = ScannedData.newBuilder() @@ -75,6 +85,9 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for canceling. + */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); signedEncryptedBallot = null; diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 62bebe3..c07d8df 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -13,17 +13,18 @@ import org.slf4j.LoggerFactory; */ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class);; public SystemConsoleOutputDevice () { super(); - logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); } - - - + /** + * Committing to the ballot. + * Simply prints to the output stream all the details in the CommitOutputCommand. + * @param command details to commit to, and the callback to call when finished + */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); PlaintextBallot plaintextBallot = command.getPlaintext(); @@ -43,16 +44,24 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { } + /** + * auditing the ballot. + * prints to the output stream the ballot secrets (the encryption randomness and its proof of random generation) + * @param command An auditing command with the callback to finally call + */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); System.out.println("Auditing"); BallotSecrets ballotSecrets = command.getBallotSecrets(); - printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); + printEncryptionRandomness(ballotSecrets.getEncryptionRandomness()); printRandomnessGenerationProof (ballotSecrets.getProof()); command.getCallback().onSuccess(null); } - + /** + * Casting the ballot (actually does nothing new) + * @param command + */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); System.out.println("Ballot finalized for casting!"); @@ -60,6 +69,10 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { } + /** + * Canceling the ballot (actually does nothing new) + * @param command + */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); System.out.println("Ballot cancelled!"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java index 2722326..564fb06 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand supplies the necessary details for outputting Audit information */ public class AuditOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java index 0c360d2..26a0388 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -3,7 +3,7 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand signals the output-device that it should Cancel the rest of the ballot output */ public class CancelOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java index af7ed30..a89eb1b 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -3,7 +3,7 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand signals the output-device that the voter wishes to Cast the ballot */ public class CastOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index dcd52f6..a3bd9ac 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand supplies the necessary details for outputting a commit to the ballot */ public class CommitOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 8a7c322..7085380 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,7 +2,9 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; -//TODO: make this class generic +/** + * Base class for the commands to put in the output-device queue + */ public abstract class OutputCommand { protected final ControllerCallback callback; From 218677fd96d2c7ae93baf223bd40b56aed656106 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 14:17:11 +0300 Subject: [PATCH 45/66] added many comments and JavaDocs --- .../output/outputcommands/OutputCommand.java | 2 + .../voting/storage/StorageManager.java | 2 +- .../voting/storage/StorageManagerMockup.java | 10 +- .../meerkat/voting/ui/SystemConsoleUI.java | 126 ++++++++++++++++-- .../meerkat/voting/ui/TickerTimerTask.java | 2 +- .../java/meerkat/voting/ui/VotingBoothUI.java | 5 +- .../ui/uicommands/CastOrAuditUICommand.java | 2 +- .../ui/uicommands/ChannelChoiceUICommand.java | 2 +- .../ui/uicommands/FatalErrorUICommand.java | 2 +- .../ui/uicommands/RaceVotingUICommand.java | 2 +- .../ui/uicommands/StartSessionUICommand.java | 2 +- .../voting/ui/uicommands/TickCommand.java | 3 +- .../voting/ui/uicommands/UICommand.java | 4 + .../ui/uicommands/WaitForFinishUICommand.java | 3 +- 14 files changed, 142 insertions(+), 25 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 7085380..342c314 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,6 +2,8 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; +//TODO: make this class generic + /** * Base class for the commands to put in the output-device queue */ diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index b9ccca7..4a70f79 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -33,7 +33,7 @@ public interface StorageManager { public Map readSystemMessages() throws IOException; - + // These are just static key identifiers for accessing the matching System Messages in the message map public final static String WAIT_FOR_COMMIT_MESSAGE = "waitForCommit"; public final static String WAIT_FOR_AUDIT_MESSAGE = "waitForAudit"; public final static String WAIT_FOR_CAST_MESSAGE = "waitForCast"; diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java index ea9ac08..f556e3b 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -1,6 +1,5 @@ package meerkat.voting.storage; -import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,7 +7,6 @@ import org.slf4j.LoggerFactory; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashMap; import java.util.Map; /** @@ -17,13 +15,15 @@ import java.util.Map; */ public class StorageManagerMockup implements StorageManager { - private boolean adminHardwareKeyInserted; - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(StorageManagerMockup.class); + public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; + private boolean adminHardwareKeyInserted; + + public StorageManagerMockup () { - logger = LoggerFactory.getLogger(StorageManagerMockup.class); logger.info("A StorageManagerMockup is constructed"); this.adminHardwareKeyInserted = false; } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index b8a3828..c4f0e83 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -18,20 +18,24 @@ import org.slf4j.LoggerFactory; import static java.lang.System.in; +/** + * an asynchronous thread implementation of the VotingBoothUI interface + * This is a mock-up implementation using just the console as our UI device + */ public class SystemConsoleUI implements VotingBoothUI, Runnable { + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleUI.class); + private BufferedReader bufferedReader; private LinkedBlockingQueue queue; - private final Logger logger; - private final int tickDurationInMillisec = 10; private Date startWaitingTime; private volatile boolean shutDownHasBeenCalled; - public SystemConsoleUI() { - logger = LoggerFactory.getLogger(SystemConsoleUI.class); + final int tickDurationInMillisec = 10; // period between view update calls + logger.info("A VB UI console is constructed"); queue = new LinkedBlockingQueue<>(); bufferedReader = new BufferedReader(new InputStreamReader(in)); @@ -44,6 +48,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * the run() method. Simply loops and takes commands from the UI's queue and handles them accordingly + */ @Override public void run () { logger.info("UI starts running"); @@ -66,6 +73,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.clear(); } + /** + * chooses the next method to run according to the type of the given UICommand. + * Special case for the TickCommand. + * As this command is registered in the queue constantly, we simply ignore this command if the UI is not in + * a waiting state + * @param command any valid UICommand + */ private void handleSingleCommand(UICommand command) { if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { @@ -103,12 +117,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * start a new session by registering a StartSessionUICommand + * @param callback - a boolean future callback to return when done + */ @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); queue.add(new StartSessionUICommand((ControllerCallback)callback)); } + /** + * welcomes the new voter at the beginning of the session + * @param command a StartSessionUICommand with a acallback + */ private void doShowWelcomeScreen(StartSessionUICommand command) { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); @@ -118,11 +140,19 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { callback.onSuccess(null); } + /** + * marks that the waiting, for something else to have happened, is finished + */ private void stopWaiting () { System.out.println (); startWaitingTime = null; } + + /** + * waits until the ENTER key is pressed in the console + * @param message a message to show the user in the console + */ private void waitForEnter(String message) { if (message != null) { System.out.println(message); @@ -141,6 +171,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the channel choice phase by registering a ChannelChoiceUICommand in the queue + * @param questions questions to determine the right voting channel for this voter + * @param callback that's where we store the answers to decide channel upon for the current voter + */ @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); @@ -148,6 +183,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(command); } + /** + * lists the channel choice questions to the voter and gathers the voter's answers + * @param command a ChannelChoiceUICommand with the data and a callback + */ private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) { logger.debug("UI: doAskChannelChoiceQuestions"); System.out.println("Showing questions for choosing channel:\n"); @@ -166,12 +205,21 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the race voting question phase by registering a RaceVotingUICommand in the queue + * @param questions all ballot questions to present to the voter + * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session + */ @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); } + /** + * lists the race voting questions to the voter and gathers the voter's answers + * @param command a RaceVotingUICommand with a callback + */ private void doAskVotingQuestions (RaceVotingUICommand command) { logger.debug("UI: doAskVotingQuestions"); System.out.println("Showing questions for race voting:\n"); @@ -190,12 +238,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the cast-or-audit phase by registering a CastOrAuditUICommand in the queue + * @param callback the returned choice of how to finalize the ballot + */ @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); } + /** + * asks the voter whether to cast or audit the ballot + * @param command a simple CastOrAuditUICommand with the callback + */ private void doCastOrAudit(CastOrAuditUICommand command) { logger.debug("UI entered doCastOrAudit"); System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); @@ -225,12 +281,21 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * makes the UI (and voter) wait for something else to happen, by registering a WaitForFinishUICommand in the queue + * @param message a message to show the user on the UI device while waiting + * @param callback a success return value of the wait (cancelling returns false) + */ @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); } + /** + * Tells the voter (in the console) to wait until some other process is finished + * @param command a simple WaitForFinishUICommand with the callback + */ public void doWaitForFinish (WaitForFinishUICommand command) { logger.debug("UI entered doWaitForFinish"); @@ -247,13 +312,23 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { System.out.print ("Waiting : ."); } + /** + * show an error to the voter. Halts the system until a technician handles it + * @param errorMessage message to show in UI device + * @param callback returns interrupt + */ @Override public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageAndHalt"); throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it."); } - + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param errorMessage message to show in UI device + * @param buttonLabels labels for buttons to present to voter + * @param callback the number of the selected button + */ @Override public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); @@ -261,6 +336,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param command a FatalErrorUICommand with the callback + */ private void doFatalError (FatalErrorUICommand command) { logger.debug("UI entered doFatalError"); @@ -301,12 +380,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * this method is run when a TickCommand was received while in waiting state + */ private void doTick () { if (startWaitingTime != null) { System.out.print ("."); // still waiting } } + /** + * get an input line from the console + * @return a line from the voter + * @throws IOException + */ private String readInputLine() throws IOException{ String s; try { @@ -323,6 +410,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * asserts that the question data matches the types that we can handle in the ConsoleUI + * (better and more sophisticated UI will be able to handle more types of data) + * @param questions list of the questions + */ private void assertQuestionsAreValid (List questions) { for (int index = 0; index < questions.size(); ++index) { BallotQuestion question = questions.get(index); @@ -339,6 +431,15 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + + /** + * present the questions to the voter console sequentially. + * Voter may choose at any time to skip a question, go back or even cancel the whole session + * @param questions list of questions to present + * @return list of answers to the questions (at the same order) + * @throws VoterCancelThrowable this is thrown if a voter chose to cancel in the middle of the process + * @throws IOException + */ private List askVoterForAnswers(List questions) throws VoterCancelThrowable, IOException { assertQuestionsAreValid (questions); @@ -348,7 +449,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { while (index < questions.size()) { BallotQuestion question = questions.get(index); System.out.println("Question number " + index); - showQuestionOnScreen(question); + showQuestionInConsole(question); System.out.println("UI screen: Enter your answer. You can also type '(b)ack' or '(c)ancel' or '(s)kip"); String s = readInputLine(); @@ -372,8 +473,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return answers; } - //show question on the screen for the voter - private void showQuestionOnScreen(BallotQuestion question) { + /** + * present a question in the console to the voter + * @param question a text ballot question + */ + private void showQuestionInConsole(BallotQuestion question) { if (!isQuestionOnlyText(question)) { System.err.println("debug: an element in question is not of TEXT type"); throw new UnsupportedOperationException(); @@ -388,6 +492,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * checks whether the data of the question is only text. This is the only type we can handle in ConsoleUI + * @param question a ballot question to check + * @return True if the question data is only text + */ private boolean isQuestionOnlyText (BallotQuestion question) { boolean isText = true; if (question.getQuestion().getType() != UIElementDataType.TEXT @@ -424,5 +533,4 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return shutDownHasBeenCalled; } - } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java index a293e5f..594fb6e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -7,7 +7,7 @@ import java.util.TimerTask; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 25/04/16. + * A thread that sends the UI clock TickCommands in a given constant frequency */ class TickerTimerTask extends TimerTask { private LinkedBlockingQueue uiQueue; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index fccb28e..c4e1f1e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -7,10 +7,13 @@ import java.util.List; /** - * An interface for the user interface component of the voting booth + * An interface for the UI component of the voting booth */ public interface VotingBoothUI { + /** + * a simple enum for the voter's finalize choice + */ public enum FinalizeBallotChoice { CAST, AUDIT diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 1b2f72f..6e18b0b 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -3,7 +3,7 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 21/04/16. + * This command signals the UI that the voter should now choose whether to Cast or Audit the ballot */ public class CastOrAuditUICommand extends UICommand { public CastOrAuditUICommand(ControllerCallback callback) { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index 5ad4391..f225ea6 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -6,7 +6,7 @@ import meerkat.voting.controller.callbacks.*; import java.util.List; /** - * Created by hai on 18/04/16. + * This command signals the UI to present channel choice questions to the voter and send back the answers */ public class ChannelChoiceUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java index 7679130..1d47700 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI that a fatal error occurred and it should notify the voter */ public class FatalErrorUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 6430e59..6b181e6 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -6,7 +6,7 @@ import meerkat.voting.controller.callbacks.*; import java.util.List; /** - * Created by hai on 18/04/16. + * This command signals the UI to present the race voting questions to the voter */ public class RaceVotingUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index 393afa7..d99313e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -3,7 +3,7 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI to present a new session to a voter */ public class StartSessionUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 0872ea3..2e2d033 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -3,7 +3,8 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This is a special UI command which just points out that a tick of the clock occurred + * (so a progress bar can advance while waiting) */ public class TickCommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index 460b7d0..4ac47a8 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -3,6 +3,10 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; //TODO: make this class generic + +/** + * Base class for the commands to put in the UI queue + */ public abstract class UICommand { protected final ControllerCallback callback; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index 5c48359..7006014 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -4,9 +4,8 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI to wait with an appropriate message until a new command replaces this state */ - public class WaitForFinishUICommand extends UICommand { private final UIElement message; From d8b766725b20b0adf0853a4ddba7a76b30ba1206 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 15:52:05 +0300 Subject: [PATCH 46/66] Removed many compilation warnings by having better handling of Generics types and better JavaDocs --- .../output/AsyncRunnableOutputDevice.java | 18 ++++++++++-------- .../voting/output/NetworkVirtualPrinter.java | 4 +++- .../output/SystemConsoleOutputDevice.java | 6 +++--- .../outputcommands/AuditOutputCommand.java | 4 ++-- .../outputcommands/CancelOutputCommand.java | 4 ++-- .../outputcommands/CastOutputCommand.java | 4 ++-- .../outputcommands/CommitOutputCommand.java | 4 ++-- .../output/outputcommands/OutputCommand.java | 8 +++----- .../ui/uicommands/CastOrAuditUICommand.java | 5 +++-- .../ui/uicommands/ChannelChoiceUICommand.java | 4 ++-- .../ui/uicommands/FatalErrorUICommand.java | 8 ++++---- .../ui/uicommands/RaceVotingUICommand.java | 4 ++-- .../ui/uicommands/StartSessionUICommand.java | 4 ++-- .../voting/ui/uicommands/TickCommand.java | 4 ++-- .../voting/ui/uicommands/UICommand.java | 10 ++++------ .../ui/uicommands/WaitForFinishUICommand.java | 4 ++-- 16 files changed, 48 insertions(+), 47 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 88dde5b..7a856a0 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -5,6 +5,8 @@ import meerkat.protobuf.Voting.BallotSecrets; import meerkat.protobuf.Voting.PlaintextBallot; import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.OutputDeviceCommitCallback; +import meerkat.voting.controller.callbacks.OutputDeviceFinalizeCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,49 +87,49 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("Output interface call to commit to ballot"); - queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (OutputDeviceCommitCallback)callback)); } @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { logger.debug("an interface call to audit"); - queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + queue.add(new AuditOutputCommand(ballotSecrets, (OutputDeviceFinalizeCallback)callback)); } @Override public void castBallot(FutureCallback callback) { logger.debug("an interface call to cast ballot"); - queue.add(new CastOutputCommand((ControllerCallback)callback)); + queue.add(new CastOutputCommand((OutputDeviceFinalizeCallback)callback)); } @Override public void cancelBallot(FutureCallback callback) { logger.debug("an interface call to cancel the output"); - queue.add(new CancelOutputCommand((ControllerCallback)callback)); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); } /** * This method should be filled by an extending class. It should have the details of how to commit to a ballot - * @param command + * @param command a CommitOutputCommand with the details and the callback */ abstract void doCommitToBallot(CommitOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to audit the ballot - * @param command + * @param command a AuditOutputCommand with the details and the callback */ abstract void doAudit(AuditOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to cast the ballot - * @param command + * @param command a CastOutputCommand with the details and the callback */ abstract void doCastBallot(CastOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to cancel the ballot output - * @param command + * @param command a CancelOutputCommand with the details and the callback */ abstract void doCancel(CancelOutputCommand command); diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index 05be623..6ec2583 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -53,6 +53,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * The NetworkVirtualPrinter actually does nothing for auditing. + * @param command a AuditOutputCommand with the details and the callback */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); @@ -63,7 +64,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * This is where the magic happens. The signed encrypted ballot is transmitted over the wire - * @param command + * @param command a CastOutputCommand with the details and the callback */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); @@ -87,6 +88,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * The NetworkVirtualPrinter actually does nothing for canceling. + * @param command a CancelOutputCommand with the callback */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index c07d8df..daf468e 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory; */ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { - private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class);; + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); public SystemConsoleOutputDevice () { super(); @@ -60,7 +60,7 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { /** * Casting the ballot (actually does nothing new) - * @param command + * @param command a CastOutputCommand with the details and the callback */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); @@ -71,7 +71,7 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { /** * Canceling the ballot (actually does nothing new) - * @param command + * @param command a CancelOutputCommand with the details and the callback */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java index 564fb06..0d4d6ea 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -6,11 +6,11 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand supplies the necessary details for outputting Audit information */ -public class AuditOutputCommand extends OutputCommand { +public class AuditOutputCommand extends OutputCommand { private final BallotSecrets ballotSecrets; - public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { + public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { super(callback); this.ballotSecrets = ballotSecrets; } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java index 26a0388..88fe03f 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand signals the output-device that it should Cancel the rest of the ballot output */ -public class CancelOutputCommand extends OutputCommand { +public class CancelOutputCommand extends OutputCommand { - public CancelOutputCommand(ControllerCallback callback) { + public CancelOutputCommand(ControllerCallback callback) { super(callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java index a89eb1b..5098cd5 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand signals the output-device that the voter wishes to Cast the ballot */ -public class CastOutputCommand extends OutputCommand { +public class CastOutputCommand extends OutputCommand { - public CastOutputCommand(ControllerCallback callback) { + public CastOutputCommand(ControllerCallback callback) { super(callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index a3bd9ac..5bec550 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -6,14 +6,14 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand supplies the necessary details for outputting a commit to the ballot */ -public class CommitOutputCommand extends OutputCommand { +public class CommitOutputCommand extends OutputCommand { private final PlaintextBallot plaintextBallot; private final SignedEncryptedBallot signedEncryptedBallot; public CommitOutputCommand(PlaintextBallot plaintextBallot, SignedEncryptedBallot signedEncryptedBallot, - ControllerCallback callback) { + ControllerCallback callback) { super(callback); this.plaintextBallot = plaintextBallot; this.signedEncryptedBallot = signedEncryptedBallot; diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 342c314..59f5ebc 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,19 +2,17 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; -//TODO: make this class generic - /** * Base class for the commands to put in the output-device queue */ -public abstract class OutputCommand { +public abstract class OutputCommand { protected final ControllerCallback callback; - protected OutputCommand(ControllerCallback callback) { + protected OutputCommand(ControllerCallback callback) { this.callback = callback; } - public ControllerCallback getCallback () { + public ControllerCallback getCallback () { return this.callback; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 6e18b0b..583a4a2 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -1,12 +1,13 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; +import meerkat.voting.ui.VotingBoothUI.FinalizeBallotChoice; /** * This command signals the UI that the voter should now choose whether to Cast or Audit the ballot */ -public class CastOrAuditUICommand extends UICommand { - public CastOrAuditUICommand(ControllerCallback callback) { +public class CastOrAuditUICommand extends UICommand { + public CastOrAuditUICommand(ControllerCallback callback) { super(callback); } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index f225ea6..185e255 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -8,11 +8,11 @@ import java.util.List; /** * This command signals the UI to present channel choice questions to the voter and send back the answers */ -public class ChannelChoiceUICommand extends UICommand { +public class ChannelChoiceUICommand extends UICommand> { private final List questions; - public ChannelChoiceUICommand(List questions, ControllerCallback callback) + public ChannelChoiceUICommand(List questions, ControllerCallback> callback) { super(callback); this.questions = questions; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java index 1d47700..98af0e4 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -6,12 +6,12 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI that a fatal error occurred and it should notify the voter */ -public class FatalErrorUICommand extends UICommand { +public class FatalErrorUICommand extends UICommand { private final UIElement errorMessage; private final UIElement[] buttonLabels; - public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) + public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) { super(callback); this.errorMessage = errorMessage; @@ -19,10 +19,10 @@ public class FatalErrorUICommand extends UICommand { } public UIElement getErrorMessage() { - return this.errorMessage; + return errorMessage; } public UIElement[] getButtonLabels() { - return this.getButtonLabels(); + return buttonLabels; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 6b181e6..9b329bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -8,11 +8,11 @@ import java.util.List; /** * This command signals the UI to present the race voting questions to the voter */ -public class RaceVotingUICommand extends UICommand { +public class RaceVotingUICommand extends UICommand> { private final List questions; - public RaceVotingUICommand(List questions, ControllerCallback callback) + public RaceVotingUICommand(List questions, ControllerCallback> callback) { super(callback); this.questions = questions; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index d99313e..b40bb5d 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI to present a new session to a voter */ -public class StartSessionUICommand extends UICommand { +public class StartSessionUICommand extends UICommand { - public StartSessionUICommand(ControllerCallback callback) { + public StartSessionUICommand(ControllerCallback callback) { super(callback); } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 2e2d033..e9bb2b7 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -6,9 +6,9 @@ import meerkat.voting.controller.callbacks.*; * This is a special UI command which just points out that a tick of the clock occurred * (so a progress bar can advance while waiting) */ -public class TickCommand extends UICommand { +public class TickCommand extends UICommand { - public TickCommand(ControllerCallback callback) { + public TickCommand(ControllerCallback callback) { super(callback); assert null == callback; } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index 4ac47a8..e579133 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -2,19 +2,17 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; -//TODO: make this class generic - /** * Base class for the commands to put in the UI queue */ -public abstract class UICommand { - protected final ControllerCallback callback; +public abstract class UICommand { + protected final ControllerCallback callback; - protected UICommand(ControllerCallback callback) { + protected UICommand(ControllerCallback callback) { this.callback = callback; } - public ControllerCallback getCallback () { + public ControllerCallback getCallback () { return this.callback; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index 7006014..5e5d504 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -6,11 +6,11 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI to wait with an appropriate message until a new command replaces this state */ -public class WaitForFinishUICommand extends UICommand { +public class WaitForFinishUICommand extends UICommand { private final UIElement message; - public WaitForFinishUICommand(UIElement message, ControllerCallback callback) + public WaitForFinishUICommand(UIElement message, ControllerCallback callback) { super(callback); this.message = message; From 2336d44ffc4bb52a13d6ee68af224252adb81efc Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 16:04:04 +0300 Subject: [PATCH 47/66] reduced more compilation warnings by having better Generics type handling and better JavaDocs --- .../selector/SimpleListCategoriesSelector.java | 2 +- .../java/meerkat/voting/ui/SystemConsoleUI.java | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index b39fede..6b8f78b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -133,7 +133,7 @@ public class SimpleListCategoriesSelector implements QuestionSelector { /** * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). * Otherwise, throws an exception. - * @param ballotAnswer + * @param ballotAnswer the answer to verify whose length is one * @param questionNumber the number of the question (needed only for error message strings) */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index c4f0e83..e35c527 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -124,7 +124,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); - queue.add(new StartSessionUICommand((ControllerCallback)callback)); + queue.add(new StartSessionUICommand((NewVoterCallback)callback)); } /** @@ -135,8 +135,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); waitForEnter(null); - ControllerCallback callback = command.getCallback(); - assert (callback instanceof NewVoterCallback); + ControllerCallback callback = command.getCallback(); callback.onSuccess(null); } @@ -179,7 +178,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback); queue.add(command); } @@ -213,7 +212,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); + queue.add(new RaceVotingUICommand(questions, (VotingCallback)callback)); } /** @@ -245,7 +244,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); - queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); + queue.add(new CastOrAuditUICommand((CastOrAuditCallback)callback)); } /** @@ -289,7 +288,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); + queue.add(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); } /** @@ -333,7 +332,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); queue.clear(); - queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } /** From 853a6b5684df06d01a1ce49d98b1f172c744aa23 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 16:05:52 +0300 Subject: [PATCH 48/66] Another (final) Generics type fix --- .../meerkat/voting/output/outputcommands/OutputCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 59f5ebc..89591fb 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -6,13 +6,13 @@ import meerkat.voting.controller.callbacks.ControllerCallback; * Base class for the commands to put in the output-device queue */ public abstract class OutputCommand { - protected final ControllerCallback callback; + protected final ControllerCallback callback; protected OutputCommand(ControllerCallback callback) { this.callback = callback; } public ControllerCallback getCallback () { - return this.callback; + return callback; } } From b1a033da5e2061bfb7362a03457a60e56252371b Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 6 Jul 2016 13:24:10 +0300 Subject: [PATCH 49/66] Add the channel identifier to the PlaintextBallot, so it is now printed by the output device --- .../src/main/proto/meerkat/voting.proto | 6 ++--- .../voting/output/NetworkVirtualPrinter.java | 23 +++++++++++++------ .../output/SystemConsoleOutputDevice.java | 5 +++- .../outputcommands/CommitOutputCommand.java | 5 ++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index c253a88..0c2963c 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -60,9 +60,9 @@ message BallotAnswer { } message PlaintextBallot { - uint64 serialNumber = 1; // Ballot serial number - - repeated BallotAnswer answers = 2; + uint64 serial_number = 1; // Ballot serial number + bytes channel_identifier = 2; + repeated BallotAnswer answers = 3; } message EncryptedBallot { diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index 6ec2583..74f9970 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -1,6 +1,7 @@ package meerkat.voting.output; import com.google.protobuf.BoolValue; +import com.google.protobuf.ByteString; import meerkat.protobuf.PollingStation.ScannedData; import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; @@ -10,10 +11,7 @@ import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; +import javax.ws.rs.client.*; import javax.ws.rs.core.Response; import java.io.IOException; @@ -25,6 +23,7 @@ import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { private static final Logger logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); + private ByteString channelIdentifier; private SignedEncryptedBallot signedEncryptedBallot; private final WebTarget successfulPrintTarget; @@ -35,6 +34,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + resetState(); } @@ -46,6 +46,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); + channelIdentifier = command.getChannelIdentifierByteString(); signedEncryptedBallot = command.getSignedEncryptedBallot(); command.getCallback().onSuccess(null); } @@ -57,7 +58,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); - signedEncryptedBallot = null; + resetState(); command.getCallback().onSuccess(null); } @@ -69,7 +70,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); ScannedData scannedData = ScannedData.newBuilder() - .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setChannel(channelIdentifier) .setSignedEncryptedBallot(this.signedEncryptedBallot) .build(); @@ -77,6 +78,8 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { BoolValue b = response.readEntity(BoolValue.class); response.close(); + resetState(); + if (b.getValue()) { command.getCallback().onSuccess(null); } @@ -92,8 +95,14 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); - signedEncryptedBallot = null; + resetState(); command.getCallback().onSuccess(null); } + + private void resetState() { + channelIdentifier = null; + signedEncryptedBallot = null; + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index daf468e..4f50c27 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -29,7 +29,10 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { logger.debug("entered method doCommitToBallot"); PlaintextBallot plaintextBallot = command.getPlaintext(); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); - System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + System.out.println("Commitment of Ballot #" + plaintextSerialNumber); + System.out.println("(channel): "); + System.out.println(bytesToString(command.getChannelIdentifierByteString())); + System.out.println("(plaintext): "); System.out.println(plaintextBallot); SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot(); long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index 5bec550..42c9307 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -1,5 +1,6 @@ package meerkat.voting.output.outputcommands; +import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; @@ -19,6 +20,10 @@ public class CommitOutputCommand extends OutputCommand { this.signedEncryptedBallot = signedEncryptedBallot; } + public ByteString getChannelIdentifierByteString() { + return plaintextBallot.getChannelIdentifier(); + } + public PlaintextBallot getPlaintext() { return plaintextBallot; } From d804f0dbacfb69849831c3763350b5c494b743a8 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 6 Jul 2016 21:33:30 +0300 Subject: [PATCH 50/66] voting-booth gradle.build now has dependencies on jetty and RESTful API for testing purposes --- voting-booth/build.gradle | 8 ++++++++ .../java/meerkat/voting/NetworkVirtualPrinterTest.java | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index ef89f86..88bd338 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -42,6 +42,14 @@ dependencies { compile project(':meerkat-common') compile project(':restful-api-common') + // Jersey for RESTful API + compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.5.+' + + // Servlets + compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.+' + compile 'org.eclipse.jetty:jetty-server:9.3.+' + compile 'org.eclipse.jetty:jetty-servlet:9.3.+' + // Logging compile 'org.slf4j:slf4j-api:1.7.7' runtime 'ch.qos.logback:logback-classic:1.1.2' diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java new file mode 100644 index 0000000..ec5cd4c --- /dev/null +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -0,0 +1,7 @@ +package meerkat.voting; + +/** + * Created by hai on 06/07/16. + */ +public class NetworkVirtualPrinterTest { +} From b667de95aa920793a032ac70a5a2141de39af429 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:49:25 +0300 Subject: [PATCH 51/66] Fix protobuf definition of EncryptedBallot to match the standard convention. --- meerkat-common/src/main/proto/meerkat/voting.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 26ac60c..6e03a5b 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -66,7 +66,7 @@ message PlaintextBallot { } message EncryptedBallot { - uint64 serialNumber = 1; // Ballot serial number + uint64 serial_number = 1; // Ballot serial number RerandomizableEncryptedMessage data = 2; } From f2836d277a47df2af1012350e699aaf5e5aa88bb Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:50:21 +0300 Subject: [PATCH 52/66] Add polling-station project dependency to VB build.gradle for testing purposes --- voting-booth/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 549788d..544f0b4 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -60,6 +60,10 @@ dependencies { testCompile 'junit:junit:4.+' runtime 'org.codehaus.groovy:groovy:2.4.+' + + // Meerkat polling station + compile project(':polling-station') + } From 5404bb9ed2139fb9536505d322d7574109621255 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:51:16 +0300 Subject: [PATCH 53/66] Fix error in setting name of output device thread --- .../src/main/java/meerkat/voting/VotingBoothToyRun.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java index dfd9b6a..65b6685 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -58,7 +58,7 @@ public class VotingBoothToyRun { Thread uiThread = new Thread(ui); uiThread.setName("Meerkat VB-UI Thread"); Thread outputThread = new Thread(outputDevice); - uiThread.setName("Meerkat VB-Output Thread"); + outputThread.setName("Meerkat VB-Output Thread"); uiThread.start(); controllerThread.start(); From 42d68b7ce88d9333acb229cc0365711dbbe8bc20 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:54:50 +0300 Subject: [PATCH 54/66] Test: Add NetworkVirtualPrinterTest --- .../voting/NetworkVirtualPrinterTest.java | 224 +++++++++++++++++- 1 file changed, 222 insertions(+), 2 deletions(-) diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java index ec5cd4c..827bf93 100644 --- a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -1,7 +1,227 @@ package meerkat.voting; + +import com.google.common.util.concurrent.FutureCallback; + +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.PollingStation.*; + +import com.google.protobuf.ByteString; +import meerkat.pollingstation.PollingStationScanner; +import meerkat.pollingstation.PollingStationWebScanner; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.OutputDeviceCommitCallback; +import meerkat.voting.controller.callbacks.OutputDeviceFinalizeCallback; +import meerkat.voting.output.NetworkVirtualPrinter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.Semaphore; + + +import static org.hamcrest.MatcherAssert.assertThat; + /** - * Created by hai on 06/07/16. + * A test for the NetworkVirtualPrinter + * coded with too much effort by Hai, based on the PollingStationWebScannerTest coded by Arbel */ + + + public class NetworkVirtualPrinterTest { -} + + private PollingStationScanner.Consumer scanner; + private static final String ADDRESS = "http://localhost"; + private static final String SUB_ADDRESS = ""; + private static final int PORT = 8080; + + private Semaphore semaphore1; + private Semaphore semaphore2; + private Throwable thrown; + private boolean dataIsAsExpected; + + private NetworkVirtualPrinter networkPrinter; + + + private class ScanHandler implements FutureCallback { + + private final ScannedData expectedData; + + public ScanHandler(ScannedData expectedData) { + this.expectedData = expectedData; + } + + @Override + public void onSuccess(ScannedData result) { + dataIsAsExpected = result.equals(expectedData); + semaphore2.release(); + } + + @Override + public void onFailure(Throwable t) { + dataIsAsExpected = false; + thrown = t; + semaphore2.release(); + } + } + + private class CommitHandler extends OutputDeviceCommitCallback { + + private boolean success; + + public CommitHandler(int requestId, long serialNumber) { + super(requestId, serialNumber, null, null); + success = false; + } + + @Override + public void onSuccess(Void v) { + System.out.println("CommitHandler success"); + success = true; + } + + @Override + public void onFailure(Throwable t) { + assertThat("Commit to ballot failed " + t.getMessage(), false); + } + + public boolean gotSuccess() { + return success; + } + } + + private class CastHandler extends OutputDeviceFinalizeCallback { + + private boolean success; + + public CastHandler(int requestId, long serialNumber) { + super(requestId, serialNumber, null, null); + success = false; + } + + @Override + public void onSuccess(Void v) { + System.out.println("CastHandler success"); + success = true; + semaphore1.release(); + } + + @Override + public void onFailure(Throwable t) { + semaphore1.release(); + assertThat("Cast ballot failed " + t.getMessage(), false); + } + + public boolean gotSuccess() { + return success; + } + } + + @Before + public void init() { + + System.err.println("Setting up Scanner WebApp!"); + + scanner = new PollingStationWebScanner(PORT, SUB_ADDRESS); + + semaphore1 = new Semaphore(0); + semaphore2 = new Semaphore(0); + thrown = null; + + try { + scanner.start(); + } catch (Exception e) { + assertThat("Could not start server: " + e.getMessage(), false); + } + + networkPrinter = new NetworkVirtualPrinter(ADDRESS + ":" + PORT); + Thread outputThread = new Thread(networkPrinter); + outputThread.setName("Meerkat VB-Output Thread"); + outputThread.start(); + + } + + @Test + public void testSuccessfulScan() throws InterruptedException { + + // create scannedData + + byte[] channel = {(byte) 1, (byte) 2}; + byte[] encMessageData = {(byte) 50, (byte) 51, (byte) 52}; + byte[] signatureData = {(byte) 93, (byte) 95, (byte) 95}; + byte[] signerId = {(byte) 17, (byte) 18, (byte) 19}; + int serialNumber = 17; + + PlaintextBallot plaintextBallot = PlaintextBallot.newBuilder() + .setChannelIdentifier(ByteString.copyFrom(channel)) + .setSerialNumber(serialNumber) + .build(); + + RerandomizableEncryptedMessage encMessage = RerandomizableEncryptedMessage.newBuilder() + .setData(ByteString.copyFrom(encMessageData)) + .build(); + + EncryptedBallot encryptedBallot = EncryptedBallot.newBuilder() + .setSerialNumber(serialNumber) + .setData(encMessage) + .build(); + + Signature signature = Signature.newBuilder() + .setType(SignatureType.ECDSA) + .setData(ByteString.copyFrom(signatureData)) + .setSignerId(ByteString.copyFrom(signerId)) + .build(); + + SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() + .setEncryptedBallot(encryptedBallot) + .setSignature(signature) + .build(); + + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(ByteString.copyFrom(channel)) + .setSignedEncryptedBallot(signedEncryptedBallot) + .build(); + + + scanner.subscribe(new ScanHandler(scannedData)); + + //Send scan + + CommitHandler commitHandler = new CommitHandler(0, serialNumber); + networkPrinter.commitToBallot(plaintextBallot, signedEncryptedBallot, commitHandler); + CastHandler castHandler = new CastHandler(1, serialNumber); + networkPrinter.castBallot(castHandler); + + + + semaphore1.acquire(); + semaphore2.acquire(); + + // Make sure the response was valid + + assertThat("Commit to ballot callback did not receive success", commitHandler.gotSuccess()); + assertThat("Cast ballot callback did not receive success", castHandler.gotSuccess()); + + assertThat("Scanner has thrown an error", thrown == null); + assertThat("Scanned data received was incorrect", dataIsAsExpected); + + } + + @After + public void close() { + + System.err.println("Scanner WebApp shutting down..."); + + try { + scanner.stop(); + } catch (Exception e) { + assertThat("Could not stop server: " + e.getMessage(), false); + } + + networkPrinter.callShutDown(); + + } + +} \ No newline at end of file From 0956fa98d37fa471ca4134fcb2e9ca85d9ca085d Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 15:23:46 +0300 Subject: [PATCH 55/66] Refactor: add comments to VotingBoothImpl.java, and rename tasks to commands (because they were two names of the same thing) Signed-off-by: Hai Brenner --- .../voting/controller/VotingBoothImpl.java | 159 +++++++++++++----- 1 file changed, 118 insertions(+), 41 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index a71dadd..92c1e5e 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -24,29 +24,30 @@ import java.util.concurrent.LinkedBlockingQueue; */ public class VotingBoothImpl implements VotingBoothController { + private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class);; + + // the component interfaces of the Voting Booth private BallotOutputDevice outputDevice; private VBCryptoManager crypto; private VotingBoothUI ui; private StorageManager storageManager; + + // election details and info private List questionsForChoosingChannel; private List questions; private QuestionSelector questionSelector; private Map systemMessages; - private LinkedBlockingQueue queue; - - private Logger logger; - + // state private ControllerState state; private volatile boolean shutDownHasBeenCalled; - + private LinkedBlockingQueue queue; protected final int MAX_REQUEST_IDENTIFIER = 100000; private static int requestCounter = 0; - + // a simple constructor public VotingBoothImpl () { - logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); shutDownHasBeenCalled = false; queue = new LinkedBlockingQueue<>(); @@ -59,11 +60,14 @@ public class VotingBoothImpl implements VotingBoothController { VotingBoothUI vbUI, StorageManager vbStorageManager) throws IOException { logger.info("init is called"); + + // keep pointers to the VB components this.outputDevice = outputDevice; this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; + // store election details and info ElectionParams electionParams; try { logger.info("init: reading election params"); @@ -92,6 +96,10 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * a method for running the Voting flow of the VB (in contrast to the admin-setup flow + * It simply loops: takes the next command in its inner queue and handles it + */ private void runVotingFlow () { logger.info("entered the voting flow"); @@ -99,11 +107,11 @@ public class VotingBoothImpl implements VotingBoothController { while (! wasShutDownCalled()) { try { - ControllerCommand task = queue.take(); - handleSingleTask (task); + ControllerCommand Command = queue.take(); + handleSingleCommand(Command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from task queue " + e); + logger.warn ("Interrupted while reading from command queue " + e); } } } @@ -117,41 +125,48 @@ public class VotingBoothImpl implements VotingBoothController { outputDevice.callShutDown(); } - private void handleSingleTask (ControllerCommand task) { - if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) { + /** + * this method decides upon a given command if to ignore it (if it has an old serial number) or to handle it + * If we choose to handle it, then it simply calls the matching method which handles this type of command + * @param command a command to handle next (probably from the inner command queue) + */ + private void handleSingleCommand(ControllerCommand command) { + // check if the command is old and should be ignored + if (command.getBallotSerialNumber() != state.currentBallotSerialNumber && !(command instanceof RestartVotingCommand)) { // probably an old command relating to some old ballot serial number. Simply log it and ignore it. - String errorMessage = "handleSingleTask: received a task too old. " + - task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; + String errorMessage = "handleSingleCommand: received a task too old. " + + command.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; logger.debug(errorMessage); return; } - if (task instanceof RestartVotingCommand) { + // decide which method to run according to the command type + if (command instanceof RestartVotingCommand) { doRestartVoting (); } - else if (task instanceof ChannelChoiceCommand) { + else if (command instanceof ChannelChoiceCommand) { doChooseChannel(); } - else if (task instanceof ChannelDeterminedCommand) { - doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); + else if (command instanceof ChannelDeterminedCommand) { + doSetChannelAndAskQuestions ((ChannelDeterminedCommand)command); } - else if (task instanceof ChooseFinalizeOptionCommand) { + else if (command instanceof ChooseFinalizeOptionCommand) { doChooseFinalizeOption(); } - else if (task instanceof CastCommand) { + else if (command instanceof CastCommand) { doFinalize(false); } - else if (task instanceof AuditCommand) { + else if (command instanceof AuditCommand) { doFinalize(true); } - else if (task instanceof EncryptAndCommitBallotCommand) { - doCommit ((EncryptAndCommitBallotCommand)task); + else if (command instanceof EncryptAndCommitBallotCommand) { + doCommit ((EncryptAndCommitBallotCommand)command); } - else if (task instanceof ReportErrorCommand) { - doReportErrorAndForceRestart((ReportErrorCommand)task); + else if (command instanceof ReportErrorCommand) { + doReportErrorAndForceRestart((ReportErrorCommand)command); } else { - logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); + logger.error("handleSingleCommand: unknown type of ControllerCommand received: " + command.getClass().getName()); doReportErrorAndForceRestart(systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -166,17 +181,28 @@ public class VotingBoothImpl implements VotingBoothController { //TODO: add commands to actually shut down the machine } + /** + * a method to execute a Restart Voting Command + */ private void doRestartVoting () { queue.clear(); state.clearAndResetState(VBState.NEW_VOTER); - ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } - private void doReportErrorAndForceRestart(ReportErrorCommand task) { - doReportErrorAndForceRestart(task.getErrorMessage()); + /** + * a (overloaded) method to execute a Report Error Command. + * It actually just runs the overloaded version of this method with the error message inside the command + * @param command the command has the info of the error message to report + */ + private void doReportErrorAndForceRestart(ReportErrorCommand command) { + doReportErrorAndForceRestart(command.getErrorMessage()); } + /** + * a (overloaded) method to report an error message to the voter + * @param errorMessage message to show the voter + */ private void doReportErrorAndForceRestart(UIElement errorMessage) { queue.clear(); state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); @@ -187,6 +213,10 @@ public class VotingBoothImpl implements VotingBoothController { this.queue)); } + /** + * a method to execute a Channel Choice Command + * it notifies the UI to present the channel choice questions to the voter + */ private void doChooseChannel () { if (state.stateIdentifier == VBState.NEW_VOTER) { logger.debug("doing chooseChannel"); @@ -203,11 +233,17 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void doSetChannelAndAskQuestions (ChannelDeterminedCommand task) { + /** + * a method to execute a Channel Determined Command + * (this actually sets the channel now after the voter has answered the channel choice questions) + * It then determines the race questions for the voter, and notifies the UI to present them to the voter + * @param command details of the voter's answers on the channel choice questions + */ + private void doSetChannelAndAskQuestions (ChannelDeterminedCommand command) { if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { logger.debug("doing set channel and ask questions"); state.stateIdentifier = VBState.ANSWER_QUESTIONS; - List channelChoiceAnswers = task.channelChoiceAnswers; + List channelChoiceAnswers = command.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, @@ -222,7 +258,10 @@ public class VotingBoothImpl implements VotingBoothController { } } - + /** + * a method to execute a Do-Finalzie-Option Command + * notifies the UI to present the cast-or-audit question to the voter + */ private void doChooseFinalizeOption() { if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) { logger.debug("doChooseFinalizeOption"); @@ -237,11 +276,17 @@ public class VotingBoothImpl implements VotingBoothController { // ignore this request } } - private void doCommit (EncryptAndCommitBallotCommand task) { + + /** + * a method to execute a Encrypt-and-Commit Command + * It sends a notification to commit to the output device + * @param command details of the voter's answers on the ballot questions + */ + private void doCommit (EncryptAndCommitBallotCommand command) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); try { - setBallotData(task); + setBallotData(command); ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_COMMIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -257,6 +302,9 @@ public class VotingBoothImpl implements VotingBoothController { } catch (SignatureException | IOException e) { logger.error("doCommit: encryption failed. exception: " + e); + + // in case the encryption failed for some unknown reason, we send the UI a notification + // to ask the voter whether he wants to retry or cancel the ballot UIElement errorMessage = systemMessages.get(StorageManager.ENCRYPTION_FAILED_MESSAGE); UIElement[] buttons = new UIElement[]{ systemMessages.get(StorageManager.RETRY_BUTTON), @@ -274,25 +322,41 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void setBallotData (EncryptAndCommitBallotCommand task) throws IOException, SignatureException{ - if (! (task instanceof RetryEncryptAndCommitBallotCommand)) { + /** + * encrypt the ballot, and keep all info (plaintext, encryption and secrets) in the state's attributes + * @param command either an EncryptAndCommitBallotCommand if we encrypt the plaintext for the first time, or a RetryEncryptAndCommitBallotCommand if we already got here but encryption failed before + * @throws IOException problems in the encryption process + * @throws SignatureException problems in the digital signature process + */ + private void setBallotData (EncryptAndCommitBallotCommand command) throws IOException, SignatureException{ + // a Retry command is given only if we first got here, and later the encryption failed but the voter chose to retry + // in such a case the plaintext is already set from previous attempt + if (! (command instanceof RetryEncryptAndCommitBallotCommand)) { // this is not a retry attempt, so the plaintext is not set yet // otherwise, we have the plaintext from the previous encryption attempt state.plaintextBallot = PlaintextBallot.newBuilder() - .setSerialNumber(task.getBallotSerialNumber()) - .addAllAnswers(task.getVotingAnswers()) + .setSerialNumber(command.getBallotSerialNumber()) + .addAllAnswers(command.getVotingAnswers()) .build(); } + + // keep the encryption and the secrets we used for it EncryptionAndSecrets encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } + /** + * a method to execute a Cast Command or an Audit Command + * according to the flag, chooses which finalize ballot task to send to the output device + * @param auditRequested true if we wish to finalize by auditing. false if we finalize by casting the ballot + */ private void doFinalize (boolean auditRequested) { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { + // finalize by auditing ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_AUDIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -305,6 +369,7 @@ public class VotingBoothImpl implements VotingBoothController { systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { + // finalize by casting the ballot ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -325,8 +390,7 @@ public class VotingBoothImpl implements VotingBoothController { - - + // an enum to keep the step (of the voting process) in which the VB is currently in private enum VBState { NEW_VOTER, CHOOSE_CHANNEL, @@ -339,6 +403,15 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * a class to keep and directly access all the details of the VB controller state. + * naming: + * - the (enum) state identifier of the current step + * - the chosen channel + * - all details of the ballot (both plaintext and encryption) + * - last request identifier (to one of the other component interfaces) + * - serial number of the current ballot + */ private class ControllerState { public VBState stateIdentifier; public byte[] channelIdentifier; @@ -359,7 +432,6 @@ public class VotingBoothImpl implements VotingBoothController { currentBallotSerialNumber = 0; } - private void clearPlaintext () { plaintextBallot = null; } @@ -379,6 +451,11 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * Creates a new request identifier to identify any call to one of the other component interfaces. + * We limit its value to MAX_REQUEST_IDENTIFIER, so the identifier is kept short. + * @return a new request identifier + */ private int generateRequestIdentifier() { ++requestCounter; if (requestCounter >= MAX_REQUEST_IDENTIFIER) { From 88991ea9ff89de02ec854557a6194fdaf35e03a5 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 15:32:22 +0300 Subject: [PATCH 56/66] Refactor: some more comments, and better looking code in VotingBoothImpl.java --- .../meerkat/voting/controller/VotingBoothImpl.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 92c1e5e..4903424 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -20,11 +20,16 @@ import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 28/03/16. + * An asynchronous implementation of the VotingBoothController. + * This implementation binds the other components (storage, ui, output device, and crypto manager), + * and runs as its own thread controlling the whole VB process. + * The high level details are that it has a queue of commands to handle in order, and a State object which keeps + * all data from previous tasks which is necessary for the next task. + * It calls executions in the UI and output device asynchronously. */ public class VotingBoothImpl implements VotingBoothController { - private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class);; + private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class); // the component interfaces of the Voting Booth private BallotOutputDevice outputDevice; @@ -34,7 +39,6 @@ public class VotingBoothImpl implements VotingBoothController { // election details and info private List questionsForChoosingChannel; - private List questions; private QuestionSelector questionSelector; private Map systemMessages; @@ -82,8 +86,8 @@ public class VotingBoothImpl implements VotingBoothController { logger.info("init: setting the election parameters"); this.questionsForChoosingChannel = electionParams.getChannelChoiceQuestionsList(); - this.questions = electionParams.getRaceQuestionsList(); - this.questionSelector = new SimpleListCategoriesSelector(this.questions, electionParams.getSelectionData()); + List questions = electionParams.getRaceQuestionsList(); + this.questionSelector = new SimpleListCategoriesSelector(questions, electionParams.getSelectionData()); logger.info("init: setting finished"); } From 1cf16d83861c264d73f9afc4e32f62df515d8bc2 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 19 Jul 2016 11:59:50 +0300 Subject: [PATCH 57/66] Fix: output device now has queue of size 1. a newer command always overrides the previous one --- .../voting/output/AsyncRunnableOutputDevice.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 7a856a0..2946d77 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -11,7 +11,7 @@ import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ArrayBlockingQueue; /** * This is a base class for simple OutputDevices which run asynchronously (as a separate thread). @@ -21,13 +21,13 @@ import java.util.concurrent.LinkedBlockingQueue; public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; - private LinkedBlockingQueue queue; + private ArrayBlockingQueue queue; private volatile boolean shutDownHasBeenCalled; public AsyncRunnableOutputDevice() { logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); logger.info("AsyncRunnableOutputDevice is constructed"); - queue = new LinkedBlockingQueue<>(); + queue = new ArrayBlockingQueue<>(1); shutDownHasBeenCalled = false; } @@ -87,24 +87,28 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("Output interface call to commit to ballot"); + queue.clear(); queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (OutputDeviceCommitCallback)callback)); } @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { logger.debug("an interface call to audit"); + queue.clear(); queue.add(new AuditOutputCommand(ballotSecrets, (OutputDeviceFinalizeCallback)callback)); } @Override public void castBallot(FutureCallback callback) { logger.debug("an interface call to cast ballot"); + queue.clear(); queue.add(new CastOutputCommand((OutputDeviceFinalizeCallback)callback)); } @Override public void cancelBallot(FutureCallback callback) { logger.debug("an interface call to cancel the output"); + queue.clear(); queue.add(new CancelOutputCommand((ControllerCallback)callback)); } From da7a05ecd8fb395f5003e6eb7461cac55a513644 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 19 Jul 2016 12:05:06 +0300 Subject: [PATCH 58/66] Fix: UI now has command queue of size 1. A new CommandPend class is introduced. It functions basically as an ArrayBlockingQueue of size 1. Difference is that it can handle two functions from two different threads - trample(cmd): removes the previously kept command (if there is such) and overrides it with the next command - offer(cmd): keeps the given command, but only if it doesn't currently keeps an older one This new functionality is used so the UI can get commands from the controller (but only take into account the latest one). At the same time it gets tick commands from its clock ticker, but only keep and handle those if it doesn't have a real controller command to handle. --- .../java/meerkat/voting/ui/CommandPend.java | 53 +++++++++++++++++++ .../meerkat/voting/ui/SystemConsoleUI.java | 30 +++++------ .../meerkat/voting/ui/TickerTimerTask.java | 12 ++--- 3 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java diff --git a/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java new file mode 100644 index 0000000..a12d3ac --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java @@ -0,0 +1,53 @@ +package meerkat.voting.ui; + +import java.util.concurrent.ArrayBlockingQueue; + +/** + * A special kind of an ArrayBlockingQueue. + * It is only of size 1, meaning it keeps only one element at most at every point of time. + * The trample function is similar to put/add except that it overrides the previously kept element. + * Other functions are similar to the matching functions in ArrayBlockingQueue. + * For instance, the offer function only "recommends" another element to keep, but if there is a stored element + * already, than this recommendation is ignored. + */ +public class CommandPend { + + private ArrayBlockingQueue queue; + + public CommandPend () { + queue = new ArrayBlockingQueue<>(1); + } + + /** + * overrides the current kept command + * @param cmd a command to override the previous one (if existed) + */ + synchronized public void trample (T cmd) { + queue.clear(); + queue.add(cmd); + } + + /** + * keeps the offered command, but only if there is no other command to handle right now + * @param cmd a command to keep if we currently do not have another + */ + synchronized public void offer (T cmd) { + queue.offer(cmd); + } + + /** + * Retrieves and removes the kept command, waiting if necessary until a command becomes available. + * @return the kept command + * @throws InterruptedException + */ + public T take() throws InterruptedException { + return queue.take(); + } + + /** + * removes the kept command + */ + synchronized public void clear () { + queue.clear(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index e35c527..3b34da8 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -8,7 +8,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; import meerkat.voting.controller.callbacks.*; import meerkat.voting.ui.uicommands.*; @@ -27,7 +26,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { private static final Logger logger = LoggerFactory.getLogger(SystemConsoleUI.class); private BufferedReader bufferedReader; - private LinkedBlockingQueue queue; + private CommandPend cmdPend; private Date startWaitingTime; private volatile boolean shutDownHasBeenCalled; @@ -37,30 +36,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { final int tickDurationInMillisec = 10; // period between view update calls logger.info("A VB UI console is constructed"); - queue = new LinkedBlockingQueue<>(); + cmdPend = new CommandPend<>(); bufferedReader = new BufferedReader(new InputStreamReader(in)); startWaitingTime = null; Timer timer = new Timer(); - timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + timer.scheduleAtFixedRate(new TickerTimerTask(cmdPend), new Date(), tickDurationInMillisec); shutDownHasBeenCalled = false; } /** - * the run() method. Simply loops and takes commands from the UI's queue and handles them accordingly + * the run() method. Simply loops and takes the UI's pending command and handles it accordingly */ @Override public void run () { logger.info("UI starts running"); while (! wasShutDownCalled()) { try { - UICommand command = queue.take(); + UICommand command = cmdPend.take(); handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); + logger.warn ("Interrupted while reading the pending command " + e); } } } @@ -70,7 +69,8 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { public void callShutDown() { logger.info("callShutDown command has been called"); shutDownHasBeenCalled = true; - queue.clear(); + stopWaiting(); + cmdPend.clear(); } /** @@ -124,7 +124,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); - queue.add(new StartSessionUICommand((NewVoterCallback)callback)); + cmdPend.trample(new StartSessionUICommand((NewVoterCallback)callback)); } /** @@ -178,8 +178,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback); - queue.add(command); + cmdPend.trample(new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback)); } /** @@ -212,7 +211,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - queue.add(new RaceVotingUICommand(questions, (VotingCallback)callback)); + cmdPend.trample(new RaceVotingUICommand(questions, (VotingCallback)callback)); } /** @@ -244,7 +243,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); - queue.add(new CastOrAuditUICommand((CastOrAuditCallback)callback)); + cmdPend.trample(new CastOrAuditUICommand((CastOrAuditCallback)callback)); } /** @@ -288,7 +287,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); + cmdPend.trample(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); } /** @@ -331,8 +330,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); - queue.clear(); - queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + cmdPend.trample(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } /** diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java index 594fb6e..42924c2 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -4,22 +4,18 @@ import meerkat.voting.ui.uicommands.TickCommand; import meerkat.voting.ui.uicommands.UICommand; import java.util.TimerTask; -import java.util.concurrent.LinkedBlockingQueue; /** * A thread that sends the UI clock TickCommands in a given constant frequency */ class TickerTimerTask extends TimerTask { - private LinkedBlockingQueue uiQueue; - public TickerTimerTask (LinkedBlockingQueue uiQueue) { - this.uiQueue = uiQueue; + private CommandPend cmdPend; + public TickerTimerTask (CommandPend cmdPend) { + this.cmdPend = cmdPend; } @Override public void run() { - UICommand t = uiQueue.peek(); - if ((t != null) && !(t instanceof TickCommand)) { - uiQueue.add(new TickCommand(null)); - } + cmdPend.offer(new TickCommand(null)); } } From ae357541e833fd964d46c47cc5bcbe77c61a1686 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 27 Jul 2016 14:25:09 +0300 Subject: [PATCH 59/66] Fix typo in documentation comment --- .../src/main/java/meerkat/crypto/dkg/feldman/Protocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index d81c75a..84cff0b 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -33,7 +33,7 @@ public class Protocol extends VerifiableSecretSharing { Waiting, /** - * Party gave invalid answer to conplaint. + * Party gave invalid answer to complaint. */ Disqualified, From cb65103fcaa84be2f94f5718fb25263e54ff8b31 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 31 Jul 2016 17:43:58 +0300 Subject: [PATCH 60/66] Fix: typo in comment --- .../src/main/java/meerkat/crypto/dkg/feldman/User.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index 6563dfd..f7c4624 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -436,7 +436,7 @@ public class User implements Runnable { /** * complaint message is valid if: * 1. it was received in broadcast chanel - * 2. the sender didn't complained against id before + * 2. the sender didn't complain against id before */ protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){ int i = sender; From aea84d0f543018dea10bb81bddde1899605fcb0e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 31 Jul 2016 17:44:24 +0300 Subject: [PATCH 61/66] Add: todo comments --- .../src/main/java/meerkat/crypto/dkg/feldman/Protocol.java | 1 + .../java/meerkat/crypto/secretsharing/shamir/Polynomial.java | 1 + 2 files changed, 2 insertions(+) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index 84cff0b..f612b07 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -79,6 +79,7 @@ public class Protocol extends VerifiableSecretSharing { * it must be chosen such that computing discrete logarithms is hard in this group. * @param encoder Encode/Decode group elements (of type T) to/from byte array */ + //TODO: why the use of regular Random? Should it be changed? public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g , Group group, int id, ByteEncoder encoder) { super(t, n, zi, random, q, g,group); diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java index 58f38fb..b00aec5 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java @@ -198,6 +198,7 @@ public class Polynomial implements Comparable { @Override public boolean equals(Object obj) { + //TODO: is this implementation correct? cannot understand its logic (hai) if(!super.equals(obj)) return false; Point other = (Point)obj; From afed4fb51003957aeda4abe17f5483f5fd36b06e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:13:10 +0300 Subject: [PATCH 62/66] Fix: reading protobuf BoolValues through network used to fail due to problematic dynamic casting --- .../src/main/java/meerkat/rest/ProtobufMessageBodyReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java index d09e213..ebf80a0 100644 --- a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java +++ b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java @@ -32,7 +32,7 @@ public class ProtobufMessageBodyReader implements MessageBodyReader { InputStream entityStream) throws IOException, WebApplicationException { try { Method newBuilder = type.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type); + Message.Builder builder = (Message.Builder) newBuilder.invoke(type); return builder.mergeFrom(entityStream).build(); } catch (Exception e) { throw new WebApplicationException(e); From c78b78aa3c96c71400d1d2baa26e271c79a67864 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:22:21 +0300 Subject: [PATCH 63/66] no change --- .../java/meerkat/voting/output/AsyncRunnableOutputDevice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 2946d77..0052a2c 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -40,7 +40,7 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); + logger.warn("Interrupted while reading from command queue " + e); } } } From 4ddd5f852a8f6ab07376b08b947b5c9ed3c1cdec Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:24:25 +0300 Subject: [PATCH 64/66] Fix: better test of the NetworkVirtualPrinter --- .../voting/NetworkVirtualPrinterTest.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java index 827bf93..80c9b72 100644 --- a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -37,6 +37,7 @@ public class NetworkVirtualPrinterTest { private static final String SUB_ADDRESS = ""; private static final int PORT = 8080; + private Semaphore semaphore0; private Semaphore semaphore1; private Semaphore semaphore2; private Throwable thrown; @@ -45,6 +46,9 @@ public class NetworkVirtualPrinterTest { private NetworkVirtualPrinter networkPrinter; + + + private class ScanHandler implements FutureCallback { private final ScannedData expectedData; @@ -70,9 +74,11 @@ public class NetworkVirtualPrinterTest { private class CommitHandler extends OutputDeviceCommitCallback { private boolean success; + public String errorMessage; public CommitHandler(int requestId, long serialNumber) { super(requestId, serialNumber, null, null); + errorMessage = null; success = false; } @@ -80,11 +86,13 @@ public class NetworkVirtualPrinterTest { public void onSuccess(Void v) { System.out.println("CommitHandler success"); success = true; + semaphore0.release(); } @Override public void onFailure(Throwable t) { - assertThat("Commit to ballot failed " + t.getMessage(), false); + errorMessage = "Commit to ballot failed " + t.getMessage(); + semaphore0.release(); } public boolean gotSuccess() { @@ -95,9 +103,11 @@ public class NetworkVirtualPrinterTest { private class CastHandler extends OutputDeviceFinalizeCallback { private boolean success; + public String errorMessage; public CastHandler(int requestId, long serialNumber) { super(requestId, serialNumber, null, null); + errorMessage = null; success = false; } @@ -110,8 +120,8 @@ public class NetworkVirtualPrinterTest { @Override public void onFailure(Throwable t) { + errorMessage = "Cast to ballot failed " + t.getMessage(); semaphore1.release(); - assertThat("Cast ballot failed " + t.getMessage(), false); } public boolean gotSuccess() { @@ -126,6 +136,7 @@ public class NetworkVirtualPrinterTest { scanner = new PollingStationWebScanner(PORT, SUB_ADDRESS); + semaphore0 = new Semaphore(0); semaphore1 = new Semaphore(0); semaphore2 = new Semaphore(0); thrown = null; @@ -136,11 +147,11 @@ public class NetworkVirtualPrinterTest { assertThat("Could not start server: " + e.getMessage(), false); } + networkPrinter = new NetworkVirtualPrinter(ADDRESS + ":" + PORT); Thread outputThread = new Thread(networkPrinter); outputThread.setName("Meerkat VB-Output Thread"); outputThread.start(); - } @Test @@ -191,12 +202,14 @@ public class NetworkVirtualPrinterTest { CommitHandler commitHandler = new CommitHandler(0, serialNumber); networkPrinter.commitToBallot(plaintextBallot, signedEncryptedBallot, commitHandler); + + semaphore0.acquire(); + CastHandler castHandler = new CastHandler(1, serialNumber); networkPrinter.castBallot(castHandler); - - semaphore1.acquire(); + semaphore2.acquire(); // Make sure the response was valid From ce40a04ac73db6e6122d070637950f50502d318d Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 7 Aug 2016 17:04:23 +0300 Subject: [PATCH 65/66] Make code of SDKG test prettier --- .../meerkat/crypto/dkg/gjkr/SDKGTest.java | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java index e4550f0..d172c23 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java @@ -10,6 +10,7 @@ import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; import meerkat.crypto.utils.BigIntegerByteEncoder; import meerkat.crypto.utils.GenerateRandomPrime; +import meerkat.protobuf.Crypto; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; @@ -20,10 +21,7 @@ import org.junit.internal.runners.statements.Fail; import static org.junit.Assert.*; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -42,58 +40,57 @@ public class SDKGTest { BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); Group group = new Zpstar(p); Arithmetic arithmetic = new Fp(q); - int t = 1; - int n = 20; + int initialT = 17; + int initialN = 20; Random rand = new Random(1); public void oneTest(Testable testable) throws Exception { - for (int i = 0; i < testable.sdkgs.length ; i++){ + for (int i = 0; i < testable.sdkgs.length; i++){ testable.futures[i] = executorService.submit(testable.sdkgs[i]); } - for (int i = 0; i < testable.futures.length ; i++){ - testable.futures[i].get(); + for (Future ftr : testable.futures) { + ftr.get(); } // got the right public value - BigInteger publicValue = group.multiply(testable.g,testable.secret); - for (int i: testable.valids){ - assert (testable.sdkgs[i - 1].getPublicValue().equals(publicValue)); + BigInteger publicValue = group.multiply(testable.g, testable.secret); + for (int i : testable.valids){ + assertEquals (testable.sdkgs[i-1].getPublicValue(), publicValue); } // assert valid verification values BigInteger expected,verification; - for (int i: testable.valids){ + for (int i : testable.valids){ expected = group.multiply(testable.g, testable.sdkgs[i - 1].getShare().y); verification = VerifiableSecretSharing.computeVerificationValue(i, testable.sdkgs[i - 1].getCommitments(), group); - assert (expected.equals(verification)); + assertEquals (expected, verification); } // restore the secret from shares - ArrayList sharesList = new ArrayList(); + ArrayList sharesList = new ArrayList<>(); - for (int i: testable.valids){ + for (int i : testable.valids){ sharesList.add(testable.sdkgs[i - 1].getShare()); } Polynomial.Point[] shares = new Polynomial.Point[sharesList.size()]; - for (int i = 0; i < shares.length; i ++){ - shares[i] = sharesList.get(i); - } + shares = sharesList.toArray(shares); - BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic); - assert (calculatedSecret.equals(testable.secret)); + BigInteger calculatedSecret = SecretSharing.recoverSecret(shares, arithmetic); + assertEquals (calculatedSecret, testable.secret); } @Test - public void test() throws Exception { + public void runSharingProtocol() throws Exception { Testable testable; for (int i = 0; i < NUM_TESTS; i++) { - testable = new Testable(n, t, group, q, rand); + testable = new Testable(initialN+i, initialT+i, group, q, rand); oneTest(testable); } } + static class Testable { Set valids; Set QUAL; @@ -118,14 +115,14 @@ public class SDKGTest { this.q = q; this.random = random; this.sdkgs = new User[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); + this.valids = new HashSet<>(); + this.QUAL = new HashSet<>(); + this.aborted = new HashSet<>(); + this.malicious = new HashSet<>(); this.futures = new Future[n]; this.g = sampleGenerator(random); - this.h = group.multiply(g,randomIntModQ(random)); - ArrayList ids = new ArrayList(); + this.h = group.multiply(g, randomIntModQ(random)); + List ids = new ArrayList<>(); for (int id = 1; id<= n ; id++){ ids.add(id); } @@ -139,8 +136,8 @@ public class SDKGTest { id = ids.remove(random.nextInt(ids.size())); s = randomIntModQ(random); channel = channels.getChannel(id); - sdkg = new Protocol(t, n, s, random, q, g , h, group, id,encoder); - sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg); + sdkg = new Protocol<>(t, n, s, random, q, g , h, group, id, encoder); + sdkgs[id - 1] = randomSDKGUser(id, channel, sdkg); if(QUAL.contains(id)){ this.secret = this.secret.add(s).mod(q); } @@ -159,7 +156,7 @@ public class SDKGTest { case HONEST: valids.add(id); QUAL.add(id); - return new User(sdkg,channel); + return new User<>(sdkg,channel); case FAILSTOP: int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 @@ -167,13 +164,13 @@ public class SDKGTest { if (abortStage > 1){ QUAL.add(id); } - return new SDKGUserImplAbort(sdkg,channel,abortStage); + return new SDKGUserImplAbort(sdkg, channel, abortStage); case MALICIOUS: malicious.add(id); - Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); + Set falls = DKGMaliciousUser.selectFallsRandomly(valids, random); + Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg, channel, random); + return new SDKGMaliciousUserImpl(sdkg, maliciousSDKG, channel, falls); } fail("Unknown user type"); @@ -203,4 +200,6 @@ public class SDKGTest { } } + + } From f2ea4b5d15b8f3311e93f74a1d87e98f6be1f088 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Thu, 11 Aug 2016 13:36:09 +0300 Subject: [PATCH 66/66] Typo: fix typo in documentation --- mixer/src/main/java/meerkat/mixer/prover/Prover.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mixer/src/main/java/meerkat/mixer/prover/Prover.java b/mixer/src/main/java/meerkat/mixer/prover/Prover.java index 303c560..d540974 100644 --- a/mixer/src/main/java/meerkat/mixer/prover/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/prover/Prover.java @@ -16,7 +16,7 @@ import java.util.Random; /** * implements of Mix2ZeroKnowledgeProver interface - * this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext + * this implementation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext */ public class Prover implements Mix2ZeroKnowledgeProver {