diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java deleted file mode 100644 index 70f611f..0000000 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ /dev/null @@ -1,20 +0,0 @@ -package meerkat.crypto.mixnet; - -import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -/** - * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. - */ -public interface Mix2ZeroKnowledgeProver { - public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - boolean switched,int i,int j, int layer, // switch info - Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException; - - -} diff --git a/mixer/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/mixer/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java new file mode 100644 index 0000000..3a11c0e --- /dev/null +++ b/mixer/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -0,0 +1,20 @@ +package meerkat.crypto.mixnet; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. + */ +public interface Mix2ZeroKnowledgeProver { + public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx, // switch info + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException; + + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java b/mixer/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java similarity index 100% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java rename to mixer/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/mixer/src/main/java/meerkat/crypto/mixnet/Mixer.java similarity index 100% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java rename to mixer/src/main/java/meerkat/crypto/mixnet/Mixer.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java b/mixer/src/main/java/meerkat/crypto/mixnet/MixerOutput.java similarity index 83% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java rename to mixer/src/main/java/meerkat/crypto/mixnet/MixerOutput.java index 1de10f5..770dc92 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java +++ b/mixer/src/main/java/meerkat/crypto/mixnet/MixerOutput.java @@ -9,5 +9,6 @@ import meerkat.protobuf.Mixing; public interface MixerOutput { public Mixing.Mix2Proof[][] getProofs(); public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages(); - public int getN(); + public int getLogN(); + public int getNumLayers(); } diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java b/mixer/src/main/java/meerkat/crypto/mixnet/Trustee.java similarity index 100% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java rename to mixer/src/main/java/meerkat/crypto/mixnet/Trustee.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java b/mixer/src/main/java/meerkat/crypto/mixnet/Verifier.java similarity index 100% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java rename to mixer/src/main/java/meerkat/crypto/mixnet/Verifier.java diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java index ea3580d..b61c4c5 100644 --- a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java +++ b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java @@ -15,37 +15,6 @@ import java.util.List; * 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 @@ -55,8 +24,13 @@ public class BatchConverter { List result = new ArrayList(); + Mixing.MixBatchHeader header = Mixing.MixBatchHeader.newBuilder() + .setLogN(mixerOutput.getLogN()) + .setLayers(mixerOutput.getNumLayers()) + .build(); + result.add(BulletinBoardAPI.BatchChunk.newBuilder() - .setData(Integer2ByteString(n)) + .setData(header.toByteString()) .build()); for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) { @@ -85,10 +59,11 @@ public class BatchConverter { public MixerOutput BatchChunkList2MixerOutput (List batchChunkList) throws Exception { - if (n != ByteString2Integer(batchChunkList.remove(0).getData())){ - throw new Exception(); - } + Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseFrom(batchChunkList.remove(0).getData()); + int logN = header.getLogN(); + int n = 1 << logN; + int layers = header.getLayers(); int nDiv2 = n >>1; Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2]; for (int layer = 0; layer < layers; layer++) @@ -110,7 +85,7 @@ public class BatchConverter { } } - return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions); + return new meerkat.mixer.mixing.MixerOutput(logN, 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 28892fa..c9d72d9 100644 --- a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java +++ b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java @@ -21,19 +21,14 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback batchHandlers = new ArrayList(prevBatchIds.size()); BatchHandler currentBatchHandler; for (Integer prevBatchId : prevBatchIds) { - currentBatchHandler = new BatchHandler(n, layers,verifier); + currentBatchHandler = new BatchHandler(verifier); asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); batchHandlers.add(currentBatchHandler); } @@ -99,7 +94,7 @@ public class MainMixing { private void updateBB(MixerOutput mixerOutput , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { - BatchConverter batchConverter = new BatchConverter(n,layers); + BatchConverter batchConverter = new BatchConverter(); List batchChunkList = batchConverter.MixerOutput2BatchChunk(mixerOutput); asyncBulletinBoardClient.postBatch(id, batchId, batchChunkList, callback); } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java deleted file mode 100644 index 99f041e..0000000 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java +++ /dev/null @@ -1,214 +0,0 @@ -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 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 a304e2f..0b6e184 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java @@ -80,89 +80,96 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { /** * generate new random mix network - * @param n number of votes + * @param logN log number of votes * @param random * @return new random mix network */ - private MixNetwork generateMixNetwork(int n,Random random){ - return new MixNetwork(new RandomPermutation(n,random)); + private PermutationNetwork generateMixNetwork(int logN, Random random){ + BenesNetwork net = new BenesNetwork(logN); + RandomPermutation perm = new RandomPermutation(1 << logN, random); + net.setPermutation(perm.permutation); + return net; } + /** - * fills the encryption table with rerandomize encrypted votes. - * @param layers + * fills the encryption table with rerandomized encrypted votes. * @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 + private void rerandomize(PermutationNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { Switch[] switchesLayer; int index1,index2; - RerandomizableEncryptedMessage e1,e2; + RerandomizableEncryptedMessage a,b; 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]; + int layers = mixNetwork.getNumLayers(); - 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); + int numSwitches = mixNetwork.getNumInputs() >>> 1; + for (int layer = 0; layer < layers; layer++) { + for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) { + boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx); + + int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx); + int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1); + + r1 = randomnesses[layer][2 * switchIdx]; + r2 = randomnesses[layer][2 * switchIdx + 1]; + + a = encryptionTable[layer][2 * switchIdx]; + b = encryptionTable[layer][2 * switchIdx + 1]; + + if (isCrossed) { + encryptionTable[layer + 1][out0] = encryptor.rerandomize(b, r2); + encryptionTable[layer + 1][out1] = encryptor.rerandomize(a, r1); } else { - encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); - encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); + encryptionTable[layer + 1][out0] = encryptor.rerandomize(a, r1); + encryptionTable[layer + 1][out1] = encryptor.rerandomize(b, r2); } + } } } /** * 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 Mix2Proof[][] generateMix2ProofTable(int n, int layers, MixNetwork mixNetwork + private Mix2Proof[][] generateMix2ProofTable(PermutationNetwork mixNetwork , RerandomizableEncryptedMessage[][] encryptionTable , EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + int layers = mixNetwork.getNumLayers(); + int n = mixNetwork.getNumInputs(); Switch[] switchesLayer; int index1,index2; int switchIndex = 0; - int nDiv2 = n >> 1; - Mix2Proof[][] proofsTable = new Mix2Proof[layers][nDiv2]; + int numSwitches = n >> 1; + Mix2Proof[][] proofsTable = new Mix2Proof[layers][numSwitches]; - RerandomizableEncryptedMessage e1,e2; + RerandomizableEncryptedMessage a,b,c,d; 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]; + for (int layer = 0; layer < layers; layer++) { + for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) { + boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx); + int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx); + int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1); + + a = encryptionTable[layer][2 * switchIdx]; + b = encryptionTable[layer][2 * switchIdx + 1]; + c = encryptionTable[layer + 1][out0]; + d = encryptionTable[layer + 1][out1]; + r1 = randomnesses[layer][2 * switchIdx]; + r2 = randomnesses[layer][2 * switchIdx + 1]; 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; + prover.prove(a, b, c, d, isCrossed, layer, switchIdx, out0, out1, r1, r2); } } return proofsTable; @@ -180,14 +187,18 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { int n = ciphertexts.size(); assert (n > 1 && isPowerOfTwo(n)); - int layers = MixNetwork.numberOfLayers(n); // layers = 2logn -1 + int logN = Integer.numberOfTrailingZeros(Integer.highestOneBit(n)) + 1; + + PermutationNetwork net = generateMixNetwork(logN,random); + + int layers = net.getNumLayers(); RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts); EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random); - MixNetwork mixNetwork = generateMixNetwork(n,random); - rerandomize(layers,mixNetwork,encryptionTable,randomnesses); - Mix2Proof[][] proofsTable = generateMix2ProofTable(n,layers,mixNetwork,encryptionTable,randomnesses); - return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable); + rerandomize(net,encryptionTable,randomnesses); + Mix2Proof[][] proofsTable = generateMix2ProofTable(net,encryptionTable,randomnesses); + + return new meerkat.mixer.mixing.MixerOutput(logN, 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 eef60a4..146a13d 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java @@ -13,26 +13,23 @@ import java.io.IOException; * implements meerkat.crypto.mixnet.MixerOutput interface * container for meerkat.mixer.mixing.mix result. */ -public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ +public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput { private final Mixing.Mix2Proof[][] proofs; private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; - private final int n; - private final int layers; + private final int logN; /** * constructor - * @param n number of votes - * @param layers + * @param logN log (base 2) of the number of votes * @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.Mix2Proof[][] proofs + public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs , Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { this.proofs = proofs; this.encryptedMessages = encryptedMessages; - this.n = n; - this.layers = layers; + this.logN = logN; } @@ -48,8 +45,13 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ } @Override - public int getN() { - return n; + public int getLogN() { + return logN; + } + + @Override + public int getNumLayers() { + return 2 * logN - 1; } /** @@ -57,33 +59,33 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ * @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]); - } - } - } +// 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 @@ -91,19 +93,19 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ * @param proof * @throws IOException */ - private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException { - Mixing.Mix2Proof.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 writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException { +// Mixing.Mix2Proof.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 diff --git a/mixer/src/main/java/meerkat/mixer/proofs/DlogConjunction.java b/mixer/src/main/java/meerkat/mixer/proofs/DlogConjunction.java new file mode 100644 index 0000000..57afa34 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/DlogConjunction.java @@ -0,0 +1,39 @@ +package meerkat.mixer.proofs; + +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.Mixing; + +import java.util.Random; + +/** + * Sigma protocol for plaintext equivalence of a pair of ciphertexts. + */ +public class DlogConjunction { + + public static class Prover + extends SigmaProtocolAnd2.Prover { + + public Prover(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.AndStatement statement, + ECElGamalMixStatementGenerator.AndStatementWitness witness) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, new SchnorrDlogEquivalence.Prover(encryptor, rand, statement.clauses[0], witness.witnesses[0]), + new SchnorrDlogEquivalence.Prover(encryptor, rand, statement.clauses[1], witness.witnesses[1])); + + } + } + + public static class Simulator extends SigmaProtocolAnd2.Simulator { + public Simulator(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.AndStatement statement) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, + new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement.clauses[0]), new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement.clauses[1])); + } + } + + public static class Verifier + extends SigmaProtocolAnd2.Verifier { + + public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.AndStatement statement) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, + new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[0]), new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[1])); + } + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java deleted file mode 100644 index f14ae3d..0000000 --- a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java +++ /dev/null @@ -1,184 +0,0 @@ -package meerkat.mixer.proofs; - -import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.concrete.Util; -import meerkat.protobuf.ConcreteCrypto.GroupElement; -import meerkat.protobuf.Mixing; -import meerkat.protobuf.Mixing.Mix2Proof.AndProof; -import meerkat.protobuf.Mixing.Mix2Proof.DlogProof; -import org.bouncycastle.math.ec.ECPoint; -import org.factcenter.qilin.primitives.concrete.ECGroup; - -import java.math.BigInteger; -import java.util.Random; - -import static meerkat.protobuf.Mixing.Mix2Proof.DlogProof.*; - -/** - * Prover, Simulator and Verifier - */ -public class ECElGamalMixProtocols { - final ECElGamalMixParams params; - final ECGroup group; - final ECElGamalEncryption encryptor; - final ECPoint g; - final ECPoint h; - final Random rand; - - - final ChallengeGenerator challengeGenerator = new ChallengeGenerator(); - - public ECElGamalMixProtocols(ECElGamalMixParams params, Random rand) { - this.params = params; - this.rand = rand; - group = params.group; - encryptor = params.encryptor; - g = params.g; - h = params.h; - } - - public class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator { - @Override - public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); } - - @Override - public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); } - } - - - public class DlogStatementSchnorrProver implements SigmaProtocol.Prover { - ECElGamalMixParams.DlogStatement statement; - ECElGamalMixParams.DlogStatementWitness witness; - - BigInteger r = null; - - public DlogStatementSchnorrProver(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) { - this.statement = statement; - this.witness = witness; - } - - @Override - public FirstMessage getFirstMessage() { - r = encryptor.generateRandomExponent(rand); - ECPoint gr = group.multiply(statement.g, r); - ECPoint hr = group.multiply(statement.h, r); - - FirstMessage firstMessage = FirstMessage.newBuilder() - .setGr(encryptor.encodeElement(gr)) - .setHr(encryptor.encodeElement(hr)) - .build(); - - return firstMessage; - } - - @Override - public FinalMessage getFinalMessage(BigInteger challenge) { - return FinalMessage.newBuilder() - .setXcr(Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound()))) - .build(); - } - - @Override - public void reset() { r = null; } - } - - public class DlogStatementSchnorrVerifier implements SigmaProtocol.Verifier { - final ECElGamalMixParams.DlogStatement statement; - - public DlogStatementSchnorrVerifier(ECElGamalMixParams.DlogStatement statement) { - this.statement = statement; - } - - @Override - public boolean verify(FirstMessage firstMessage, BigInteger challenge, - FinalMessage finalMessage) { - GroupElement grEncoded = firstMessage.getGr(); - ECPoint gr = encryptor.decodeElement(grEncoded); - - GroupElement hrEncoded = firstMessage.getHr(); - ECPoint hr = encryptor.decodeElement(hrEncoded); - - BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr()); - - boolean gGood = group.add(gr, group.multiply(statement.a,challenge)).equals(group.multiply(statement.g,xcr)); - boolean hGood = group.add(hr, group.multiply(statement.b,challenge)).equals(group.multiply(statement.h,xcr)); - return gGood && hGood; - } - - } - - public class DlogStatementSchnorrSimulator implements SigmaProtocol.Simulator { - ECElGamalMixParams.DlogStatement statement; - BigInteger response = null; - - public DlogStatementSchnorrSimulator(ECElGamalMixParams.DlogStatement statement) { - this.statement = statement; - } - - @Override - public FirstMessage getFirstMessage(BigInteger challenge) { - response = encryptor.generateRandomExponent(rand); - - ECPoint u = group.multiply(statement.g, response).subtract(group.multiply(statement.a,challenge)); - ECPoint v = group.multiply(statement.h, response).subtract(group.multiply(statement.b,challenge)); - return FirstMessage.newBuilder() - .setGr(encryptor.encodeElement(u)) - .setHr(encryptor.encodeElement(v)) - .build(); - } - - @Override - public FinalMessage getFinalMessage() { - - return FinalMessage.newBuilder() - .setXcr(Util.encodeBigInteger(response)) - .build(); - } - - @Override - public void reset() { response = null; } - } - - /** - * Prover for plaintext equivalence of a pair of ciphertexts. - */ - public class AndStatementProver - extends SigmaProtocolAnd2.Prover { - public AndStatementProver(ECElGamalMixParams.AndStatement statement, - ECElGamalMixParams.AndStatementWitness witness) { - super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, new DlogStatementSchnorrProver(statement.clauses[0], witness.witnesses[0]), - new DlogStatementSchnorrProver(statement.clauses[1], witness.witnesses[1])); - } - } - - public class AndStatementVerifier - extends SigmaProtocolAnd2.Verifier { - public AndStatementVerifier(ECElGamalMixParams.AndStatement statement) { - super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, - new DlogStatementSchnorrVerifier(statement.clauses[0]), new DlogStatementSchnorrVerifier(statement.clauses[1])); - } - } - - public class AndStatementSimulator extends SigmaProtocolAnd2.Simulator { - public AndStatementSimulator(ECElGamalMixParams.AndStatement statement) { - super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, - new DlogStatementSchnorrSimulator(statement.clauses[0]), new DlogStatementSchnorrSimulator(statement.clauses[1])); - } - } - - public class Mix2Prover extends SigmaProtocolOr2.Prover { - public Mix2Prover(ECElGamalMixParams.Mix2Statement statement, ECElGamalMixParams.Mix2StatementWitness witness) { - super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator, - new AndStatementProver(statement.clauses[witness.trueClauseIndex], witness.witness), - new AndStatementSimulator(statement.clauses[1 - witness.trueClauseIndex]), - witness.trueClauseIndex); - } - } - - public class Mix2Verifier extends SigmaProtocolOr2.Verifier { - public Mix2Verifier(ECElGamalMixParams.Mix2Statement statement) { - super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator, - new AndStatementVerifier(statement.clauses[0]), new AndStatementVerifier(statement.clauses[1])); - } - } -} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixStatementGenerator.java similarity index 96% rename from mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java rename to mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixStatementGenerator.java index 273d435..8f43dff 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixStatementGenerator.java @@ -16,7 +16,7 @@ import java.math.BigInteger; * * both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it */ -public class ECElGamalMixParams { +public class ECElGamalMixStatementGenerator { final ECElGamalEncryption encryptor; final ECGroup group; @@ -31,7 +31,7 @@ public class ECElGamalMixParams { * @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and * second base (h) are taken from the encryptor (second base is the public key) */ - public ECElGamalMixParams(ECElGamalEncryption encryptor){ + public ECElGamalMixStatementGenerator(ECElGamalEncryption encryptor){ this.encryptor = encryptor; this.group = encryptor.getGroup(); this.g = group.getGenerator(); @@ -40,11 +40,6 @@ public class ECElGamalMixParams { this.hEncoded = encryptor.encodeElement(h); } - public enum TrueCouple { - left, right, unknown - } - - /** * can be used by anyone, e.g meerkat.mixer.verifier * @@ -84,7 +79,7 @@ public class ECElGamalMixParams { * * The actual stored data is a cached representation for use in proofs and verification. This consists of the four substatements that are ORs of the DLOG equality. * - * A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixParams (all constructors are private) + * A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixStatementGenerator (all constructors are private) * */ public class Mix2Statement { @@ -180,9 +175,9 @@ public class ECElGamalMixParams { DlogStatement(ECPoint a, ECPoint b) { - this.g = ECElGamalMixParams.this.g; + this.g = ECElGamalMixStatementGenerator.this.g; this.a = a; - this.h = ECElGamalMixParams.this.h; + this.h = ECElGamalMixStatementGenerator.this.h; this.b = b; } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Mix2.java b/mixer/src/main/java/meerkat/mixer/proofs/Mix2.java new file mode 100644 index 0000000..616b7fd --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/Mix2.java @@ -0,0 +1,46 @@ +package meerkat.mixer.proofs; + +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.Mixing; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Sigma protocol for proving correctness of a 2x2 switch + */ +public class Mix2 { + public static class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator { + ECElGamalEncryption encryptor; + ECGroup group; + Random rand; + + public ChallengeGenerator(ECElGamalEncryption encryptor, Random rand) { + this.encryptor = encryptor; + group = encryptor.getGroup(); + } + + @Override + public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); } + + @Override + public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); } + } + + public static class Prover extends SigmaProtocolOr2.Prover { + public Prover(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.Mix2Statement statement, ECElGamalMixStatementGenerator.Mix2StatementWitness witness) { + super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, rand), + new DlogConjunction.Prover(encryptor, rand, statement.clauses[witness.trueClauseIndex], witness.witness), + new DlogConjunction.Simulator(encryptor, rand, statement.clauses[1 - witness.trueClauseIndex]), + witness.trueClauseIndex); + } + } + + public static class Verifier extends SigmaProtocolOr2.Verifier { + public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.Mix2Statement statement) { + super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, null), + new DlogConjunction.Verifier(encryptor, statement.clauses[0]), new DlogConjunction.Verifier(encryptor, statement.clauses[1])); + } + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java index 9fd2662..2710f0c 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java @@ -2,7 +2,6 @@ package meerkat.mixer.proofs; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.concrete.Util; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; @@ -26,8 +25,7 @@ public class Prover implements Mix2ZeroKnowledgeProver { private final ECElGamalEncryption encryptor; private final ECPoint g,h; private final BigInteger groupOrderUpperBound; - private final ECElGamalMixParams mixParams; - final ECElGamalMixProtocols mixProtocols; + private final ECElGamalMixStatementGenerator mixParams; final SigmaFiatShamir mix2NIZK; /** @@ -43,9 +41,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { this.group = this.encryptor.getGroup(); this.g = group.getGenerator(); this.h = this.encryptor.getElGamalPK().getPK(); - this.mixParams = new ECElGamalMixParams(encryptor); + this.mixParams = new ECElGamalMixStatementGenerator(encryptor); this.groupOrderUpperBound = group.orderUpperBound(); - this.mixProtocols = new ECElGamalMixProtocols(mixParams, rand); // We don't need randomness for the verifier this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle); } @@ -55,8 +52,6 @@ public class Prover implements Mix2ZeroKnowledgeProver { * @param c - if switched then c = rerandomize(b,r2) else c = rerandomize(a,r1) * @param d - if switched then d = rerandomize(a,r1) else d = rerandomize(b,r2) * @param switched - trueClauseIndex - * @param i - column of a and c in encryption table - * @param j - column of b and d in encryption table * @param layer - row of a,b in encryption table * @param r1 * @param r2 @@ -67,186 +62,25 @@ public class Prover implements Mix2ZeroKnowledgeProver { Crypto.RerandomizableEncryptedMessage b, Crypto.RerandomizableEncryptedMessage c, Crypto.RerandomizableEncryptedMessage d, - boolean switched,int i,int j, int layer, + boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx, + Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { - ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(a,b,c,d); - ECElGamalMixParams.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched); + ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(a, b, c, d); + ECElGamalMixStatementGenerator.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched); - ECElGamalMixProtocols.Mix2Prover prover = mixProtocols.new Mix2Prover(statement, witness); + Mix2.Prover prover = new Mix2.Prover(encryptor, rand, statement, witness); Mixing.Mix2Proof.Location location = Mixing.Mix2Proof.Location.newBuilder() - .setI(i) - .setJ(j) - .setLayer(layer).build(); + .setLayer(layer) + .setSwitchIdx(switchIdx) + .setOut0(out0Idx) + .setOut1(out1Idx) + .build(); return mix2NIZK.generateNizk(prover).toBuilder().setLocation(location).build(); - -// Mixing.Mix2Proof first,second,third,fourth; -// -// ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched); -// -// first = createOrProof(statement.getDlogStatement(0)); -// second = createOrProof(statement.getDlogStatement(1)); -// third = createOrProof(statement.getDlogStatement(2)); -// fourth = createOrProof(statement.getDlogStatement(3)); -// -// 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; } -// -// -// Mixing.Mix2Proof.DlogProof.FirstMessage createDlogProof(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) { -// -// BigInteger r = encryptor.generateRandomExponent(rand); -// ECPoint gr = group.multiply(statement.g, r); -// ECPoint hr = group.multiply(statement.h, r); -// -// Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() -// .setGr(group.encode(gr)) -// .setHr(group.encode(hr)) -// .build(); -// -// BigInteger challenge = Prover.hash() -// } -// -// -// -// -// /** -// * Generate a ZK proof that there exists x s.t (g ^ x == a and h ^ x == b) or (g' ^ x == a and h' ^ x == b). -// * -// * For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g}(a)==log_{g}(b)): -// *
    -// *
  1. Prover chooses a random r, and sends g^r, h^r
  2. -// *
  3. Verifier chooses a random c and sends c
  4. -// *
  5. Prover computes
  6. -// *
-// * -// * -// * @param orStatement -// * @return ZKP OrProof: -// * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs -// */ -// private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) { -// -// ECPoint g1 = orStatement.g1; -// ECPoint h1 = orStatement.h1; -// ECPoint g2 = orStatement.g2; -// ECPoint h2 = orStatement.h2; -// -// ECPoint g1Tag = orStatement.g1Tag; -// ECPoint h1Tag = orStatement.h1Tag; -// ECPoint g2Tag = orStatement.g2Tag; -// ECPoint h2Tag = orStatement.h2Tag; -// -// // Randomness for the ZK proof -// BigInteger r = encryptor.generateRandomExponent(rand); -// -// -// BigInteger c1,c2,z,zTag; -// ECPoint u,v,uTag,vTag; -// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage; -// -// -// switch (orStatement.trueClauseIndex) { -// case left: -// c2 = encryptor.generateRandomExponent(rand); -// zTag = encryptor.generateRandomExponent(rand); -// //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 -// firstMessage = -// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() -// .setG1(orStatement.g1Encoded) -// .setH1(orStatement.h1Encoded) -// .setG2(orStatement.g2Encoded) -// .setH2(orStatement.h2Encoded) -// .setG1Tag(orStatement.g1TagEncoded) -// .setH1Tag(orStatement.h1TagEncoded) -// .setG2Tag(orStatement.g2TagEncoded) -// .setH2Tag(orStatement.h2TagEncoded) -// .setU(encryptor.encodeElement(u)) -// .setV(encryptor.encodeElement(v)) -// .setUTag(encryptor.encodeElement(uTag)) -// .setVTag(encryptor.encodeElement(vTag)) -// .build(); -// c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); -// //step 3 -// //z = (r + c1 * x) % group size; -// z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); -// break; -// case right: -// c1 = encryptor.generateRandomExponent(rand); -// z = encryptor.generateRandomExponent(rand); -// //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 -// firstMessage = -// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() -// .setG1(orStatement.g1Encoded) -// .setH1(orStatement.h1Encoded) -// .setG2(orStatement.g2Encoded) -// .setH2(orStatement.h2Encoded) -// .setG1Tag(orStatement.g1TagEncoded) -// .setH1Tag(orStatement.h1TagEncoded) -// .setG2Tag(orStatement.g2TagEncoded) -// .setH2Tag(orStatement.h2TagEncoded) -// .setU(encryptor.encodeElement(u)) -// .setV(encryptor.encodeElement(v)) -// .setUTag(encryptor.encodeElement(uTag)) -// .setVTag(encryptor.encodeElement(vTag)) -// .build(); -// c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); -// //step 3 -// //zTag = (r + c2 * x) % group size; -// zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); -// break; -// default: -// return null; -// } -// -// -// return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() -// .setG1(firstMessage.getG1()) -// .setH1(firstMessage.getH1()) -// .setG2(firstMessage.getG2()) -// .setH2(firstMessage.getH2()) -// .setG1Tag(firstMessage.getG1()) -// .setH1Tag(firstMessage.getH1Tag()) -// .setG2Tag(firstMessage.getG2Tag()) -// .setH2Tag(firstMessage.getH2Tag()) -// .setU(firstMessage.getU()) -// .setV(firstMessage.getV()) -// .setUTag(firstMessage.getUTag()) -// .setVTag(firstMessage.getVTag()) -// .setC1(Util.encodeBigInteger(c1)) -// .setC2(Util.encodeBigInteger(c2)) -// .setZ(Util.encodeBigInteger(z)) -// .setZTag(Util.encodeBigInteger(zTag)) -// .build(); -// } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SchnorrDlogEquivalence.java b/mixer/src/main/java/meerkat/mixer/proofs/SchnorrDlogEquivalence.java new file mode 100644 index 0000000..49d615f --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/SchnorrDlogEquivalence.java @@ -0,0 +1,123 @@ +package meerkat.mixer.proofs; + +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.concrete.Util; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Schnorr's ZK proof of Dlog equivlance + */ +public class SchnorrDlogEquivalence { + + public static class Verifier implements SigmaProtocol.Verifier { + ECElGamalEncryption encryptor; + ECGroup group; + final ECElGamalMixStatementGenerator.DlogStatement statement; + + public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.DlogStatement statement) { + this.encryptor = encryptor; + group = encryptor.getGroup(); + this.statement = statement; + } + + @Override + public boolean verify(Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage, BigInteger challenge, + Mixing.Mix2Proof.DlogProof.FinalMessage finalMessage) { + ConcreteCrypto.GroupElement grEncoded = firstMessage.getGr(); + ECPoint gr = encryptor.decodeElement(grEncoded); + + ConcreteCrypto.GroupElement hrEncoded = firstMessage.getHr(); + ECPoint hr = encryptor.decodeElement(hrEncoded); + + BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr()); + + boolean gGood = group.add(gr, group.multiply(statement.a, challenge)).equals(group.multiply(statement.g, xcr)); + boolean hGood = group.add(hr, group.multiply(statement.b, challenge)).equals(group.multiply(statement.h, xcr)); + return gGood && hGood; + } + + } + + public static class Simulator implements SigmaProtocol.Simulator { + ECElGamalEncryption encryptor; + ECGroup group; + Random rand; + + ECElGamalMixStatementGenerator.DlogStatement statement; + BigInteger response = null; + + public Simulator(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.DlogStatement statement) { + this.encryptor = encryptor; + group = encryptor.getGroup(); + this.rand = rand; + this.statement = statement; + } + + @Override + public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage(BigInteger challenge) { + response = encryptor.generateRandomExponent(rand); + + ECPoint u = group.multiply(statement.g, response).subtract(group.multiply(statement.a, challenge)); + ECPoint v = group.multiply(statement.h, response).subtract(group.multiply(statement.b, challenge)); + return Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() + .setGr(encryptor.encodeElement(u)) + .setHr(encryptor.encodeElement(v)) + .build(); + } + + @Override + public Mixing.Mix2Proof.DlogProof.FinalMessage getFinalMessage() { + + return Mixing.Mix2Proof.DlogProof.FinalMessage.newBuilder() + .setXcr(Util.encodeBigInteger(response)) + .build(); + } + } + + public static class Prover implements SigmaProtocol.Prover { + ECElGamalEncryption encryptor; + ECGroup group; + Random rand; + ECElGamalMixStatementGenerator.DlogStatement statement; + ECElGamalMixStatementGenerator.DlogStatementWitness witness; + + BigInteger r = null; + + public Prover(ECElGamalEncryption encryptor, Random rand, + ECElGamalMixStatementGenerator.DlogStatement statement, ECElGamalMixStatementGenerator.DlogStatementWitness witness) { + this.encryptor = encryptor; + group = encryptor.getGroup(); + this.rand = rand; + this.statement = statement; + this.witness = witness; + } + + @Override + public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage() { + r = encryptor.generateRandomExponent(rand); + ECPoint gr = group.multiply(statement.g, r); + ECPoint hr = group.multiply(statement.h, r); + + Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() + .setGr(encryptor.encodeElement(gr)) + .setHr(encryptor.encodeElement(hr)) + .build(); + + return firstMessage; + } + + @Override + public Mixing.Mix2Proof.DlogProof.FinalMessage getFinalMessage(BigInteger challenge) { + return Mixing.Mix2Proof.DlogProof.FinalMessage.newBuilder() + .setXcr(Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound()))) + .build(); + } + + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java index 6dbac42..d0640c5 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java @@ -12,23 +12,11 @@ public interface SigmaProtocol { public interface Prover { public FirstMsgType getFirstMessage(); public FinalMessageType getFinalMessage(BigInteger challenge); - - /** - * Reset the prover (so the next calls to {@link #getFirstMessage()} will - * start a new proof. - */ - public void reset(); } public interface Simulator { public FirstMsgType getFirstMessage(BigInteger challenge); public FinalMessageType getFinalMessage(); - - /** - * Reset the prover (so the next calls to {@link #getFirstMessage(BigInteger)} will - * start a new proof. - */ - public void reset(); } public interface Verifier { diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java index d9e473b..31a0151 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java @@ -29,10 +29,6 @@ public class SigmaProtocolAnd2 { public FinalMessageOut getFinalMessage(BigInteger challenge) { return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(challenge)); } - - - @Override - public void reset() { provers[0].reset(); provers[1].reset(); } } static public class Verifier @@ -142,9 +139,6 @@ public class SigmaProtocolOr2 { public FinalMessageOut getFinalMessage() { return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage()); } - - @Override - public void reset() { simulators[0].reset(); simulators[1].reset(); } } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java index 5cf98d9..0331cce 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java @@ -8,7 +8,6 @@ import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.ECGroup; -import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier; /** * implements Mix2ZeroKnowledgeVerifier @@ -16,11 +15,11 @@ import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier; public class Verifier implements Mix2ZeroKnowledgeVerifier { + private final ECElGamalEncryption encryptor; private final ECGroup group; private final RandomOracle randomOracle; private final ECPoint g,h; - private final ECElGamalMixParams mixParams; - final ECElGamalMixProtocols mixProtocols; + private final ECElGamalMixStatementGenerator mixParams; final SigmaFiatShamir mix2NIZK; @@ -32,12 +31,12 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { * @param randomOracle should be as the random oracle used by meerkat.mixer.proofs */ 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.mixParams = new ECElGamalMixParams(encryptor); - this.mixProtocols = new ECElGamalMixProtocols(mixParams, null); // We don't need randomness for the verifier + this.mixParams = new ECElGamalMixStatementGenerator(encryptor); this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle); // this.parser = new ZeroKnowledgeOrProofParser(group); } @@ -60,8 +59,8 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { Crypto.RerandomizableEncryptedMessage out2, Mixing.Mix2Proof proof) throws InvalidProtocolBufferException { - ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2); - Mix2Verifier verifier = mixProtocols.new Mix2Verifier(statement); + ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2); + Mix2.Verifier verifier = new Mix2.Verifier(encryptor, statement); return mix2NIZK.verifyNizk(proof, verifier); } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java b/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java index 36d39ac..4d58fee 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java @@ -16,20 +16,17 @@ 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) + public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier, MixerOutput mixerOutput) throws InvalidProtocolBufferException { - int index1,index2,layer; + int out0,out1,layer, switchIdx; - //assert n = 2^k - if ( (n &(n-1)) != 0) - throw new IllegalArgumentException("n"); - int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1; + int layers = mixerOutput.getNumLayers(); + int n = 1 << mixerOutput.getLogN(); //initialize locationChecksum table // use for check BeneshNet validity boolean[][] locationChecksum = new boolean[layers][n]; @@ -44,36 +41,32 @@ public final class VerifyTable { for (int j = 0; j < Mix2Proofs[i].length ; j ++){ Mixing.Mix2Proof zkp = Mix2Proofs[i][j]; Mixing.Mix2Proof.Location location = zkp.getLocation(); - index1 = location.getI(); - index2 = location.getJ(); + out0 = location.getOut0(); + out1 = location.getOut1(); layer = location.getLayer(); + switchIdx = location.getSwitchIdx(); // check location validity - if (layer > layers >> 1) { - if (index2 - index1 != n >> (layers - layer)) - return false; - } - else{ - if (index2 - index1 != n >> (layer + 1)) - return false; - } + // TODO: add check +// if (layer > layers >> 1) { +// if (out1 - out0 != n >> (layers - layer)) +// return false; +// } +// else{ +// if (out1 - out0 != n >> (layer + 1)) +// return false; +// } // mark location in table - locationChecksum[layer][index1] = true; - locationChecksum[layer][index2] = true; + locationChecksum[layer][2 * switchIdx] = true; + locationChecksum[layer][2 * switchIdx + 1] = true; // verify proof - if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1], - rerandomizableEncryptedMessages[layer][index2], - rerandomizableEncryptedMessages[layer + 1][index1], - rerandomizableEncryptedMessages[layer + 1][index2], + if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx], + rerandomizableEncryptedMessages[layer][2 * switchIdx + 1], + rerandomizableEncryptedMessages[layer + 1][out0], + rerandomizableEncryptedMessages[layer + 1][out1], zkp)) { - - verifier.verify(rerandomizableEncryptedMessages[layer][index1], - rerandomizableEncryptedMessages[layer][index2], - rerandomizableEncryptedMessages[layer + 1][index1], - rerandomizableEncryptedMessages[layer + 1][index2], - zkp); return false; } } diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/mixer/src/main/proto/meerkat/mixing.proto similarity index 70% rename from meerkat-common/src/main/proto/meerkat/mixing.proto rename to mixer/src/main/proto/meerkat/mixing.proto index eebce4b..0755948 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/mixer/src/main/proto/meerkat/mixing.proto @@ -7,6 +7,11 @@ option java_package = "meerkat.protobuf"; import 'meerkat/crypto.proto'; import 'meerkat/concrete_crypto.proto'; +message MixBatchHeader { + int32 logN = 1; // log (base 2) of number of inputs to mix + int32 layers = 2; // Number of layers in mix +} + message Plaintext { bytes data = 1; } @@ -44,13 +49,19 @@ message Mix2Proof { BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0 } - message Location{ - int32 i = 1; - int32 j = 2; - int32 layer = 3; + + // Location of the + message Location { + int32 layer = 1; // layer in which the switch is placed + int32 switchIdx = 2; // idx of the switch + int32 out0 = 3; // idx of the first output ciphertext (in layer+1 of the ciphertext matrix) + int32 out1 = 4; // idx of the second output ciphertext (in layer+1 of the ciphertext matrix) } + FirstMessage firstMessage = 1; FinalMessage finalMessage = 2; Location location = 5; } + + diff --git a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java index 1690aa5..0893a71 100644 --- a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java +++ b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java @@ -1,100 +1,100 @@ -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.proofs.Prover; -import meerkat.mixer.proofs.Verifier; -import meerkat.mixer.proofs.VerifyTable; -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 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(Utils.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(prover,encryptor); - - // 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 = Utils.genRandomBallot(2,3,16); - result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); - } - return result; - } - //@SimpleRerandomizeTest - public void createValidTest() throws IOException { - - List mixerInput = generateMixerInput(); - System.out.println("start mixing"); - 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.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); - System.out.println("all done"); - } - - //@SimpleRerandomizeTest - public void createInvalidTest() throws IOException { - - //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true); - //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true); - //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier); - - List mixerInput = generateMixerInput(); - System.out.println("start mixing"); - 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.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); - System.out.println("all done"); - } -} +//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.proofs.Prover; +//import meerkat.mixer.proofs.Verifier; +//import meerkat.mixer.proofs.VerifyTable; +//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 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(Utils.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(prover,encryptor); +// +// // 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 = Utils.genRandomBallot(2,3,16); +// result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); +// } +// return result; +// } +// //@SimpleRerandomizeTest +// public void createValidTest() throws IOException { +// +// List mixerInput = generateMixerInput(); +// System.out.println("start mixing"); +// 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.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); +// System.out.println("all done"); +// } +// +// //@SimpleRerandomizeTest +// public void createInvalidTest() throws IOException { +// +// //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true); +// //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true); +// //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier); +// +// List mixerInput = generateMixerInput(); +// System.out.println("start mixing"); +// 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.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); +// System.out.println("all done"); +// } +//} diff --git a/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java b/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java index aec3619..710b8fc 100644 --- a/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java @@ -77,7 +77,7 @@ public class Mix2ProofTest extends ECParamTestBase { group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2())))); - Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2); + Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0, 0, r1,r2); assertTrue (verifier.verify(e1,e2,e1New,e2New, proof)); } diff --git a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java deleted file mode 100644 index 0245726..0000000 --- a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java +++ /dev/null @@ -1,46 +0,0 @@ -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; - -public class MixNetworkTest { - - @Test - public void testMixNetwork() throws Exception{ - - Random random = new Random(1); - int logn = 10; - 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)); - - } - -} diff --git a/mixer/src/test/java/meerkat/mixer/MixingTest.java b/mixer/src/test/java/meerkat/mixer/MixingTest.java index df5b8aa..693baee 100644 --- a/mixer/src/test/java/meerkat/mixer/MixingTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixingTest.java @@ -45,7 +45,7 @@ public class MixingTest extends ECParamTestBase { mixer = new Mixer(prover, enc); // generate n - int logN = 9; // + random.nextInt(8) + int logN = 5; // + random.nextInt(8) layers = 2*logN - 1; n = 1 << logN; } @@ -76,7 +76,7 @@ public class MixingTest extends ECParamTestBase { System.out.println("start verification"); startTime = System.currentTimeMillis(); - assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); + assert (VerifyTable.verifyTable(verifier,mixerOutput)); finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); diff --git a/mixer/src/test/java/meerkat/mixer/proofs/DlogAndStatementSigmaTest.java b/mixer/src/test/java/meerkat/mixer/proofs/DlogAndStatementSigmaTest.java index 50c232a..562cac6 100644 --- a/mixer/src/test/java/meerkat/mixer/proofs/DlogAndStatementSigmaTest.java +++ b/mixer/src/test/java/meerkat/mixer/proofs/DlogAndStatementSigmaTest.java @@ -11,8 +11,8 @@ import java.math.BigInteger; public class DlogAndStatementSigmaTest extends SigmaProtocolTest { final DlogStatementSchnorrSigmaTest dlogtest; - ECElGamalMixParams.DlogStatement s1, s2; - ECElGamalMixParams.DlogStatementWitness w1, w2; + ECElGamalMixStatementGenerator.DlogStatement s1, s2; + ECElGamalMixStatementGenerator.DlogStatementWitness w1, w2; public DlogAndStatementSigmaTest() { this.dlogtest = new DlogStatementSchnorrSigmaTest(); @@ -20,10 +20,10 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest s1w1 = dlogtest.returnRandomTrueStatement(); + Pair s1w1 = dlogtest.returnRandomTrueStatement(); s1 = s1w1.a; w1 = s1w1.b; - Pair s2w2 = dlogtest.returnRandomTrueStatement(); + Pair s2w2 = dlogtest.returnRandomTrueStatement(); s2 = s2w2.a; w2 = s2w2.b; } @@ -36,19 +36,19 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest getNewProver() { return new SigmaProtocolAnd2.Prover<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, - dlogtest.prots.new DlogStatementSchnorrProver(s1, w1), dlogtest.prots.new DlogStatementSchnorrProver(s2, w2)); + new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s1, w1), new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s2, w2)); } @Override protected SigmaProtocol.Verifier getNewVerifier() { return new SigmaProtocolAnd2.Verifier<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, - dlogtest.prots.new DlogStatementSchnorrVerifier(s1), dlogtest.prots.new DlogStatementSchnorrVerifier(s2)); + new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s1), new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s2)); } @Override protected SigmaProtocol.Simulator getNewSimulator() { return new SigmaProtocolAnd2.Simulator<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, - dlogtest.prots.new DlogStatementSchnorrSimulator(s1), dlogtest.prots.new DlogStatementSchnorrSimulator(s2)); + new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s1), new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s2)); } @Override diff --git a/mixer/src/test/java/meerkat/mixer/proofs/DlogOrStatementSigmaTest.java b/mixer/src/test/java/meerkat/mixer/proofs/DlogOrStatementSigmaTest.java index a352d42..d305b87 100644 --- a/mixer/src/test/java/meerkat/mixer/proofs/DlogOrStatementSigmaTest.java +++ b/mixer/src/test/java/meerkat/mixer/proofs/DlogOrStatementSigmaTest.java @@ -11,8 +11,8 @@ import java.math.BigInteger; public class DlogOrStatementSigmaTest extends SigmaProtocolTest { final DlogStatementSchnorrSigmaTest dlogtest; - final ECElGamalMixParams.AndStatement[] statements = new ECElGamalMixParams.AndStatement[2]; - ECElGamalMixParams.AndStatementWitness w; + final ECElGamalMixStatementGenerator.AndStatement[] statements = new ECElGamalMixStatementGenerator.AndStatement[2]; + ECElGamalMixStatementGenerator.AndStatementWitness w; int trueStatementIndex; @@ -23,53 +23,57 @@ public class DlogOrStatementSigmaTest extends SigmaProtocolTest s1w1 = dlogtest.returnRandomTrueStatement(); - Pair s2w2 = dlogtest.returnRandomTrueStatement(); - ECElGamalMixParams.AndStatement trueStatement = dlogtest.params.new AndStatement(s1w1.a, s2w2.a); - w = dlogtest.params.new AndStatementWitness(s1w1.b, s2w2.b); + Pair s1w1 = dlogtest.returnRandomTrueStatement(); + Pair s2w2 = dlogtest.returnRandomTrueStatement(); + ECElGamalMixStatementGenerator.AndStatement trueStatement = dlogtest.statementGenerator.new AndStatement(s1w1.a, s2w2.a); + w = dlogtest.statementGenerator.new AndStatementWitness(s1w1.b, s2w2.b); statements[trueStatementIndex] = trueStatement; - ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement(); - ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement(); + ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement(); + ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement(); - ECElGamalMixParams.AndStatement falseStatement = dlogtest.params.new AndStatement(f1, f2); + ECElGamalMixStatementGenerator.AndStatement falseStatement = dlogtest.statementGenerator.new AndStatement(f1, f2); statements[1 - trueStatementIndex] = falseStatement; } @Override void generateRandomFalseStatement() { - ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement(); - ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement(); + ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement(); + ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement(); - statements[0] = dlogtest.params.new AndStatement(f1, f2); + statements[0] = dlogtest.statementGenerator.new AndStatement(f1, f2); f1 = dlogtest.returnRandomFalseStatement(); f2 = dlogtest.returnRandomFalseStatement(); - statements[1] = dlogtest.params.new AndStatement(f1, f2); + statements[1] = dlogtest.statementGenerator.new AndStatement(f1, f2); } @Override protected SigmaProtocol.Prover getNewProver() { - SigmaProtocol.Prover andProver = dlogtest.prots.new AndStatementProver(statements[trueStatementIndex], w); - SigmaProtocol.Simulator andSimulator = dlogtest.prots.new AndStatementSimulator(statements[1 - trueStatementIndex]); + SigmaProtocol.Prover andProver = new DlogConjunction.Prover(dlogtest.encryptor, rand, statements[trueStatementIndex], w); + SigmaProtocol.Simulator andSimulator = new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1 - trueStatementIndex]); + Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand); return new SigmaProtocolOr2.Prover<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, - dlogtest.prots.challengeGenerator, andProver, andSimulator, trueStatementIndex); + gen, andProver, andSimulator, trueStatementIndex); } @Override protected SigmaProtocol.Verifier getNewVerifier() { + Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand); return new SigmaProtocolOr2.Verifier(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, - dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementVerifier(statements[0]), dlogtest.prots.new AndStatementVerifier(statements[1])); + gen, new DlogConjunction.Verifier(dlogtest.encryptor, statements[0]), new DlogConjunction.Verifier(dlogtest.encryptor, statements[1])); } @Override protected SigmaProtocol.Simulator getNewSimulator() { + + Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand); return new SigmaProtocolOr2.Simulator<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, - dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementSimulator(statements[0]), - dlogtest.prots.new AndStatementSimulator(statements[1])); + gen, new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[0]), + new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1])); } @Override diff --git a/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java b/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java index 868bce0..1da4e21 100644 --- a/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java +++ b/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java @@ -1,8 +1,10 @@ package meerkat.mixer.proofs; +import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.mixer.ECParamTestBase; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.util.Pair; import java.math.BigInteger; @@ -13,42 +15,44 @@ import java.math.BigInteger; public class DlogStatementSchnorrSigmaTest extends SigmaProtocolTest { - ECParamTestBase ecParams = new ECParamTestBase(); - ECElGamalMixParams params; - ECElGamalMixProtocols prots; + ECParamTestBase ecParams; + ECElGamalMixStatementGenerator statementGenerator; + ECElGamalEncryption encryptor; + ECGroup group; - ECElGamalMixParams.DlogStatement statement; - ECElGamalMixParams.DlogStatementWitness witness; - ECElGamalMixProtocols.DlogStatementSchnorrProver prover; - ECElGamalMixProtocols.DlogStatementSchnorrVerifier verifier; - ECElGamalMixProtocols.DlogStatementSchnorrSimulator simulator; + ECElGamalMixStatementGenerator.DlogStatement statement; + ECElGamalMixStatementGenerator.DlogStatementWitness witness; + SchnorrDlogEquivalence.Prover prover; + SchnorrDlogEquivalence.Verifier verifier; + SchnorrDlogEquivalence.Simulator simulator; public DlogStatementSchnorrSigmaTest() { - - this.params = new ECElGamalMixParams(ecParams.enc); - this.prots = new ECElGamalMixProtocols(params, rand); // We don't need randomness for the verifier + ecParams = new ECParamTestBase(); + encryptor = ecParams.enc; + group = encryptor.getGroup(); + this.statementGenerator = new ECElGamalMixStatementGenerator(ecParams.enc); } - Pair returnRandomTrueStatement() { - BigInteger x = prots.encryptor.generateRandomExponent(rand); - ECPoint a = prots.group.multiply(prots.g, x); - ECPoint b = prots.group.multiply(prots.h, x); - ECElGamalMixParams.DlogStatement statement = params.new DlogStatement(a, b); - ECElGamalMixParams.DlogStatementWitness witness = params.new DlogStatementWitness(x); + Pair returnRandomTrueStatement() { + BigInteger x = encryptor.generateRandomExponent(rand); + ECPoint a = group.multiply(statementGenerator.g, x); + ECPoint b = group.multiply(statementGenerator.h, x); + ECElGamalMixStatementGenerator.DlogStatement statement = statementGenerator.new DlogStatement(a, b); + ECElGamalMixStatementGenerator.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x); return new Pair<>(statement, witness); } - ECElGamalMixParams.DlogStatement returnRandomFalseStatement() { - ECPoint a = prots.group.sample(rand); - ECPoint b = prots.group.sample(rand); + ECElGamalMixStatementGenerator.DlogStatement returnRandomFalseStatement() { + ECPoint a = group.sample(rand); + ECPoint b = group.sample(rand); - return params.new DlogStatement(a, b); + return statementGenerator.new DlogStatement(a, b); } void generateRandomTrueStatement() { - Pair sw = returnRandomTrueStatement(); + Pair sw = returnRandomTrueStatement(); this.statement = sw.a; this.witness = sw.b; } @@ -60,24 +64,24 @@ public class DlogStatementSchnorrSigmaTest extends @Override protected SigmaProtocol.Prover getNewProver() { - prover = prots.new DlogStatementSchnorrProver(statement, witness); + prover = new SchnorrDlogEquivalence.Prover(encryptor, rand, statement, witness); return prover; } @Override protected SigmaProtocol.Verifier getNewVerifier() { - verifier = prots.new DlogStatementSchnorrVerifier(statement); + verifier = new SchnorrDlogEquivalence.Verifier(encryptor, statement); return verifier; } @Override protected SigmaProtocol.Simulator getNewSimulator() { - simulator = prots.new DlogStatementSchnorrSimulator(statement); + simulator = new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement); return simulator; } @Override protected BigInteger getChallengeModulus() { - return prots.group.orderUpperBound(); + return group.orderUpperBound(); } } \ No newline at end of file diff --git a/mixer/src/test/java/meerkat/mixer/proofs/DummySigmaProof.java b/mixer/src/test/java/meerkat/mixer/proofs/DummySigmaProof.java index 07c6c80..82d2429 100644 --- a/mixer/src/test/java/meerkat/mixer/proofs/DummySigmaProof.java +++ b/mixer/src/test/java/meerkat/mixer/proofs/DummySigmaProof.java @@ -34,11 +34,6 @@ public class DummySigmaProof { public BigInteger getFinalMessage(BigInteger challenge) { return challenge.add(r.multiply(x.add(y))); } - - @Override - public void reset() { - - } } public static class Verifier implements SigmaProtocol.Verifier { @@ -81,11 +76,6 @@ public class DummySigmaProof { public BigInteger getFinalMessage() { return resp; } - - @Override - public void reset() { - - } } } diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index d676a34..85015f4 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -75,7 +75,7 @@ public class ZeroKnowledgeProof { 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]); + false,0,0,0, 0, randomnesses[i],randomnesses[i+1]); } long finishTime = System.currentTimeMillis();