mixer project
parent
12ed7a679d
commit
a834194d50
|
@ -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
|
||||
|
|
|
@ -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<EncryptedBallot> mix(List<EncryptedBallot> ballots);
|
||||
public Pair<Mixing.ZeroKnowledgeProof[][],Crypto.RerandomizableEncryptedMessage[][]> mix(List<Crypto.RerandomizableEncryptedMessage> ciphertexts) throws InvalidProtocolBufferException;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
//}
|
||||
//
|
||||
//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;
|
||||
}
|
||||
|
|
|
@ -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<Edge> 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<Edge>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]> mix(List<RerandomizableEncryptedMessage> 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<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]>(proofsTable, encryptionsTable);
|
||||
return new Pair<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]>(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<int[]> permutaions = new ArrayBlockingQueue<int[]>(n);
|
||||
Queue<int[]> permutationsQueue = new ArrayBlockingQueue<int[]>(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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue