mixer project

mixer
tzlil.gon 2015-12-01 21:48:41 +02:00
parent 12ed7a679d
commit a834194d50
5 changed files with 122 additions and 112 deletions

View File

@ -1,4 +1,4 @@
#Mon Oct 26 15:30:44 IST 2015 #Tue Dec 01 01:04:39 IST 2015
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -1,5 +1,10 @@
package meerkat.crypto.mixnet; 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 java.util.List;
import static meerkat.protobuf.Voting.*; import static meerkat.protobuf.Voting.*;
@ -7,5 +12,5 @@ import static meerkat.protobuf.Voting.*;
* Created by talm on 25/10/15. * Created by talm on 25/10/15.
*/ */
public interface Mixer { public interface Mixer {
public List<EncryptedBallot> mix(List<EncryptedBallot> ballots); public Pair<Mixing.ZeroKnowledgeProof[][],Crypto.RerandomizableEncryptedMessage[][]> mix(List<Crypto.RerandomizableEncryptedMessage> ciphertexts) throws InvalidProtocolBufferException;
} }

View File

@ -7,44 +7,38 @@ option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto'; import 'meerkat/crypto.proto';
message ZeroKnowledgeProof { message ZeroKnowledgeProof {
message OrProof {
message GroupMember {
bytes data = 1;
}
message BigIntegerMsg {
bytes data = 1; bytes data = 1;
} }
//message ZeroKnowledgeProof { //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
// GroupMember g1 = 1;
// message OrProof{ GroupMember h1 = 2;
// message GroupMember{ GroupMember g2 = 3;
// required bytes data = 1; GroupMember h2 = 4;
// } GroupMember g1Tag = 5;
// message BigIntegerMsg{ GroupMember h1Tag = 6;
// required bytes data = 1; GroupMember g2Tag = 7;
// } GroupMember h2Tag = 8;
// //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
// required GroupMember g1 = 1; //calc: u, v, uTag, vTag;
// required GroupMember h1 = 2; GroupMember u = 9;
// required GroupMember g2 = 3; GroupMember v = 10;
// required GroupMember h2 = 4; GroupMember uTag = 11;
// required GroupMember g1Tag = 5; GroupMember vTag = 12;
// required GroupMember h1Tag = 6;
// required GroupMember g2Tag = 7; //generated: c1,c2,z,zTag
// required GroupMember h2Tag = 8; BigIntegerMsg c1 = 13;
// BigIntegerMsg c2 = 14;
// //calc: u, v, uTag, vTag; BigIntegerMsg z = 15;
// required GroupMember g2 = 9; BigIntegerMsg zTag = 16;
// required GroupMember h2 = 10; }
// required GroupMember g1Tag = 11; OrProof first = 1;
// required GroupMember h1Tag = 12; OrProof second = 2;
// OrProof third = 3;
// //generated: c1,c2,z,zTag OrProof fourth = 4;
// 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;
//}
//

View File

@ -6,78 +6,96 @@ import java.util.List;
class Graph class Graph
{ {
private int n; private int n;
private int nDiv2;
private Node[] nodes; private Node[] nodes;
protected Graph(int[] permutation){ protected Graph(int[] permutation){
n = permutation.length; // n = 2^k n = permutation.length; // n = 2^k
nDiv2 = n /2;
createNodes(); createNodes();
createEdges(permutation); createEdges(permutation);
setSwitches(); setSwitches();
} }
// provide an access to graph to algorithm result
// index must be less then n/2
protected boolean getSwitchValue(int index,boolean up) protected boolean getSwitchValue(int index,boolean up)
{ {
// index must be less then n/2
return up ? nodes[index].on : nodes[index + n / 2].on; 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() private void createNodes()
{ {
nodes = new Node[n]; nodes = new Node[n];
for (int i = 0; i < n / 2; i++) for (int i = 0; i < n / 2; i++)
{ {
nodes[i] = new Node(i, i + n / 2, true); nodes[i] = new Node(true);
nodes[i + n / 2] = new Node(i, i + n / 2, false); 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) private void createEdges(int[] permutation)
{ {
int pi1, pi2; int j;
for (int i = 0; i < n / 2; i++) for (int i = 0; i < nDiv2; i++)
{ {
pi1 = (permutation[i] < n / 2) ? permutation[i] + (n / 2) : permutation[i]; j = (permutation[i] % nDiv2) + nDiv2;
pi2 = (permutation[i + n / 2] < n / 2) ? permutation[i + n / 2] + (n / 2) : permutation[i + n / 2]; 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))); j = (permutation[i + nDiv2] % nDiv2) + nDiv2;
nodes[pi1].edges.add(new Edge(nodes[i], (permutation[i] >= n / 2))); nodes[i].edges.add(new Edge(nodes[j], (permutation[i + nDiv2] < nDiv2)));
nodes[j].edges.add(new Edge(nodes[i], (permutation[i + nDiv2] < nDiv2)));
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)));
} }
} }
// 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() 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) if (node.set)
continue; 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) while (true)
{ {
node.set = true; node.set = true;
node.on = v; node.on = v;
e0 = node.edges.get(0); e1 = node.edges.get(1);
if (node.edges.get(0).nighbor.set && node.edges.get(1).nighbor.set) if (e0.neighbor.set && e1.neighbor.set)
break; break;
v ^= (!node.edges.get(0).nighbor.set) ? node.edges.get(0).broken : node.edges.get(1).broken; v ^= (!e0.neighbor.set) ? e0.broken : e1.broken;
node = (!node.edges.get(0).nighbor.set) ? node.edges.get(0).nighbor : node.edges.get(1).nighbor; node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor;
} }
} }
} }
//inner classes
private class Node private class Node
{ {
public boolean up; public boolean up;
public List<Edge> edges; public List<Edge> edges;
public int i, j;
public boolean on; public boolean on;
public boolean set; public boolean set;
public Node(int i, int j,boolean up) public Node(boolean up)
{ {
this.i = i;
this.j = j;
this.up = up; this.up = up;
edges = new ArrayList<Edge>(); edges = new ArrayList<Edge>();
set = false; set = false;
@ -86,11 +104,11 @@ class Graph
private class Edge private class Edge
{ {
public Node nighbor; public Node neighbor;
public boolean broken; public boolean broken;
public Edge(Node nighbor, boolean broken) public Edge(Node neighbor, boolean broken)
{ {
this.nighbor = nighbor; this.neighbor = neighbor;
this.broken = broken; this.broken = broken;
} }
} }

View File

@ -1,26 +1,20 @@
package mixer; package mixer;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import com.google.protobuf.InvalidProtocolBufferException;
import javafx.util.Pair; import javafx.util.Pair;
import java.util.Random; import java.util.Random;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.Mixing.*; import meerkat.protobuf.Mixing.*;
import meerkat.crypto.Encryption; import meerkat.crypto.Encryption;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
public class Mixer{ public class Mixer implements meerkat.crypto.mixnet.Mixer{
private Random random; private Random random;
private Mix2ZeroKnowledgeProver prover; private Mix2ZeroKnowledgeProver prover;
@ -47,7 +41,7 @@ public class Mixer{
} }
layers<<=1; layers<<=1;
layers--; layers--;
RerandomizableEncryptedMessage[][] encryptionsTable = new RerandomizableEncryptedMessage[layers][n]; RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers][n];
ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2]; ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2];
boolean[][] mixnet = createMixNet(n,layers); boolean[][] mixnet = createMixNet(n,layers);
int index1, index2, switchIndex = 0; int index1, index2, switchIndex = 0;
@ -55,39 +49,40 @@ public class Mixer{
RerandomizableEncryptedMessage e1, e2; RerandomizableEncryptedMessage e1, e2;
boolean half = true; boolean half = true;
//set first level of encryptions //set first level of encryption
for (int j = 0; j < n; j++) for (int j = 0; j < n; j++)
{ {
encryptionsTable[0][j] = ciphertexts.get(j); encryptionTable[0][j] = ciphertexts.get(j);
} }
// main loop // main loop
for (int i = n, layer = 0; layer < layers; layer++) // i == permutation size 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; index1 = k + j;
index2 = k + j + i / 2; index2 = k + j + i / 2;
e1 = encryptionsTable[layer][index1]; e1 = encryptionTable[layer][index1];
e2 = encryptionsTable[layer][index2]; e2 = encryptionTable[layer][index2];
r1 = encryptor.generateRandomness(random); r1 = encryptor.generateRandomness(random);
r2 = encryptor.generateRandomness(random); r2 = encryptor.generateRandomness(random);
if (!mixnet[layer][switchIndex]) if (!mixnet[layer][switchIndex])
{ {
encryptionsTable[layer+1][index1] = encryptor.rerandomize(e1, r1); encryptionTable[layer+1][index1] = encryptor.rerandomize(e1, r1);
encryptionsTable[layer+1][index2] = encryptor.rerandomize(e2,r2); encryptionTable[layer+1][index2] = encryptor.rerandomize(e2,r2);
} }
else else
{ {
encryptionsTable[layer+1][index1] = encryptor.rerandomize(e2,r2); encryptionTable[layer+1][index1] = encryptor.rerandomize(e2,r2);
encryptionsTable[layer+1][index2] = encryptor.rerandomize(e1,r1); encryptionTable[layer+1][index2] = encryptor.rerandomize(e1,r1);
} }
proofsTable[layer][switchIndex] = proofsTable[layer][switchIndex] =
prover.prove(e1, e2, encryptionsTable[layer + 1][index1], prover.prove(e1, e2, encryptionTable[layer + 1][index1],
encryptionsTable[layer + 1][index2], encryptionTable[layer + 1][index2],
mixnet[layer][switchIndex], r1,r2); mixnet[layer][switchIndex], r1,r2);
switchIndex = (switchIndex + 1) % (n / 2); switchIndex = (switchIndex + 1) % (n / 2);
@ -99,15 +94,13 @@ public class Mixer{
if (i == 1) if (i == 1)
{ {
half = false; half = false;
i = 4; i = 4; // avoid duplicate layer in the middle
} }
} }
else else
{
i <<= 1; i <<= 1;
} }
} return new Pair<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]>(proofsTable, encryptionTable);
return new Pair<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]>(proofsTable, encryptionsTable);
} }
private int[] randomPermutation(int n){ private int[] randomPermutation(int n){
@ -130,23 +123,23 @@ public class Mixer{
private boolean[][] createMixNet(int n,int layers) private boolean[][] createMixNet(int n,int layers)
{ {
int[] permutaion = randomPermutation(n); int[] permutation = randomPermutation(n);
int[] pi, piL, piR; int[] pi, piL, piR;
Queue<int[]> permutaions = new ArrayBlockingQueue<int[]>(n); Queue<int[]> permutationsQueue = new ArrayBlockingQueue<int[]>(n);
Graph graph; Graph graph;
boolean[][] mixnet = new boolean[layers][n>>1]; 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 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); graph = new Graph(pi);
piL = new int[i / 2]; piL = new int[i / 2];
piR = 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[layers - layer - 1][k + j] = graph.getSwitchValue(k, true);
mixnet[layer][k + j] = graph.getSwitchValue(k, false); mixnet[layer][k + j] = graph.getSwitchValue(k, false);
@ -162,8 +155,8 @@ public class Mixer{
piR[k] = pi[k] % (i / 2); piR[k] = pi[k] % (i / 2);
} }
} }
permutaions.add(piL); permutationsQueue.add(piL);
permutaions.add(piR); permutationsQueue.add(piR);
} }
} }
return mixnet; return mixnet;