From 767d73c14371e1ae6c046605bc217204274b610e Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 15 Dec 2015 16:44:50 +0200 Subject: [PATCH] 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);