diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 4262012..a9b61d7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -4,11 +4,12 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.Crypto; import java.util.List; +import java.util.Random; /** * Created by talm on 25/10/15. */ public interface Mixer { - public MixerOutput mix(List ciphertexts) + public MixerOutput mix(List ciphertexts,Random random) throws InvalidProtocolBufferException; } diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java new file mode 100644 index 0000000..f2d02dd --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java @@ -0,0 +1,118 @@ +package meerkat.mixer.main; + +import com.google.protobuf.ByteString; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Tzlil on 12/17/2015. + * provide convert operation from batch data to meerkat.mixer.mixing output and backwards + */ +public class BatchConverter { + + private final int n,layers; + + /** + * constructor + * @param n + * @param layers + */ + public BatchConverter(int n,int layers){ + this.n = n; + this.layers = layers; + } + + /** + * convert integer to byte string + * @param a + * @return a as byte string + */ + private ByteString Integer2ByteString(int a){ + return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray()); + } + + /** + * convert byte string to integer + * @param bs + * @return bs as int + */ + private int ByteString2Integer(ByteString bs) { + return Integer.valueOf(bs.toString()); + } + + /** + * convert meerkat.mixer.mixing output to batch data + * @param mixerOutput + * @return meerkat.mixer.mixing output as list of batch data + */ + public List MixerOutput2BatchData(MixerOutput mixerOutput) { + + List result = new ArrayList(); + + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(Integer2ByteString(n)) + .build()); + + for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) { + for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(zkp.toByteString()) + .build()); + } + } + for (Crypto.RerandomizableEncryptedMessage[] encryptionLayer : mixerOutput.getEncryptedMessages()) { + for (Crypto.RerandomizableEncryptedMessage encryption : encryptionLayer) { + result.add(BulletinBoardAPI.BatchData.newBuilder() + .setData(encryption.toByteString()) + .build()); + } + } + return result; + } + + /** + * convert batch data list to meerkat.mixer.mixing output + * @param batchDataList + * @return batch data list as MixerOutput + * @throws Exception + */ + public MixerOutput BatchDataList2MixerOutput + (List batchDataList) throws Exception { + + if (n != ByteString2Integer(batchDataList.remove(0).getData())){ + throw new Exception(); + } + + int nDiv2 = n >>1; + Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; + for (int layer = 0; layer < layers; layer++) + { + for (int proofIndex = 0 ; proofIndex < nDiv2 ; proofIndex ++) + { + proofs[layer][proofIndex] = Mixing.ZeroKnowledgeProof.parseFrom(batchDataList.remove(0).getData()); + } + } + + Crypto.RerandomizableEncryptedMessage[][] encryptions + = new Crypto.RerandomizableEncryptedMessage[layers + 1][n]; + for (int layer = 0; layer < layers + 1; layer++) + { + for (int encryptionIndex = 0 ; encryptionIndex < n ; encryptionIndex ++) + { + encryptions[layer][encryptionIndex] = Crypto.RerandomizableEncryptedMessage + .parseFrom(batchDataList.remove(0).getData()); + } + } + + return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions); + + } + +} + diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java index dee9129..e609234 100644 --- a/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java +++ b/mixer/src/main/java/meerkat/mixer/main/BatchHandler.java @@ -1,7 +1,104 @@ package meerkat.mixer.main; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto; +import meerkat.mixer.necessary.AsyncBulletinBoardClient; +import meerkat.mixer.necessary.CompleteBatch; +import meerkat.mixer.verifier.VerifyTable; + +import java.util.Arrays; +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * implements AsyncBulletinBoardClient.ClientCallback */ -public class BatchHandler { +public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback { + + private MixerOutput mixerOutput; + private boolean msgReceived; + private Throwable t; + private CompleteBatch msg; + + private final int n, layers; + private final Mix2ZeroKnowledgeVerifier verifier; + + /** + * constructor + * @param n + * @param layers + * @param verifier + */ + public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) { + this.mixerOutput = null; + this.n = n; + this.layers = layers; + this.msgReceived = false; + this.t = null; + this.verifier = verifier; + } + + @Override + public void handleCallback(CompleteBatch msg) { + this.msg = msg; + synchronized (this) { + this.msgReceived = true; + notifyAll(); + } + } + + @Override + public void handleFailure(Throwable t) { + this.t = t; + synchronized (this) { + this.msgReceived = true; + notifyAll(); + } + } + + /** + * return true iff msg was received + * @return msgReceived + */ + public boolean isMsgReceived() { + return msgReceived; + } + + /** + * convert batch data to meerkat.mixer.mixing output + * @throws Exception + */ + private void convertMessage() throws Exception { + BatchConverter batchConverter = new BatchConverter(n,layers); + this.mixerOutput = batchConverter.BatchDataList2MixerOutput(msg.getBatchDataList()); + } + + /** + * call convert message, and if succeed verify the table + * @return return true iff the given batch message is valid meerkat.mixer.mixing output + * @throws Exception + */ + public boolean verifyTable() throws Exception { + if (mixerOutput == null) { + convertMessage(); + } + return VerifyTable.verifyTable(verifier, n, mixerOutput); + } + + /** + * extract input for meerkat.mixer.mixing from previous mixers output + * @return last layer of encrypted votes as list + * @throws Throwable in case if failure + */ + public List getInputForMixer() throws Throwable { + if (t != null) { + throw t; + } + if(!verifyTable()){ + throw new Exception("in valid table"); + } + return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1 + } } + diff --git a/mixer/src/main/java/meerkat/mixer/main/MainMixing.java b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java index 27b6fca..62978e8 100644 --- a/mixer/src/main/java/meerkat/mixer/main/MainMixing.java +++ b/mixer/src/main/java/meerkat/mixer/main/MainMixing.java @@ -1,7 +1,110 @@ package meerkat.mixer.main; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.Mixer; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.Crypto; +import meerkat.mixer.mixing.MixNetwork; +import meerkat.mixer.necessary.AsyncBulletinBoardClient; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * this class define all the operation meerkat.mixer.mixing party should do: + * 1. receive previous mixers output (re encrypted votes + proofs) + * 2. verify its input + * 3. mix + * 4. send the meerkat.mixer.mixing output */ public class MainMixing { + + private final Mixer mixer; + private final Mix2ZeroKnowledgeVerifier verifier; + private final int n, layers; + private final AsyncBulletinBoardClient asyncBulletinBoardClient; + private final byte[] id; + + + /** + * constructor + * @param mixer + * @param verifier + * @param n + * @param asyncBulletinBoardClient + * @param id + */ + public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n + , AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) { + this.mixer = mixer; + this.verifier = verifier; + this.n = n; + this.layers = MixNetwork.numberOfLayers(n); + this.asyncBulletinBoardClient = asyncBulletinBoardClient; + this.id = id; + } + + /** + * + * @param prevBatchIds + * @param batchId + * @param random + * @param callback + * @throws Throwable + */ + public void main(List prevBatchIds, int batchId, Random random, AsyncBulletinBoardClient.ClientCallback callback) throws Throwable { + + List mixerInput; + + List batchHandlers = new ArrayList(prevBatchIds.size()); + BatchHandler currentBatchHandler; + for (Integer prevBatchId : prevBatchIds) { + currentBatchHandler = new BatchHandler(n, layers,verifier); + asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler); + batchHandlers.add(currentBatchHandler); + } + // check all handlers messages were received + for (BatchHandler batchHandler : batchHandlers) { + synchronized (batchHandler){ + if(!batchHandler.isMsgReceived()) + batchHandler.wait(); + } + } + // assert all handlers succeeded + for (BatchHandler batchHandler : batchHandlers) { + if(!batchHandler.verifyTable()){ + throw new Exception("invalid input"); + } + } + + BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); + mixerInput = lastBatchHandler.getInputForMixer(); + + MixerOutput mixerOutput = mixer.mix(mixerInput,random); + updateBB(mixerOutput, batchId, callback); + + } + + /** + * send meerkat.mixer.mixing output to BB + * @param mixerOutput + * @param batchId + * @param callback + */ + private void updateBB(MixerOutput mixerOutput + , int batchId, AsyncBulletinBoardClient.ClientCallback callback) { + + BatchConverter batchConverter = new BatchConverter(n,layers); + List batchDataList = batchConverter.MixerOutput2BatchData(mixerOutput); + asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback); + } + + + + } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java index 71770ce..e820ebd 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixNetwork.java @@ -1,7 +1,214 @@ package meerkat.mixer.mixing; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/15/2015. + * contains benes mix network. + * the network is generated in the constructor and can't be change */ public class MixNetwork { + + private final Switch[][] switches; + + /** + * constructor + * @param randomPermutation + */ + public MixNetwork(RandomPermutation randomPermutation) { + this.switches = generateSwitchesValue(randomPermutation.permutation); + } + + /** + * implements benes mix network algorithm + * @param permutation - random permutation + * @return switches + */ + private Switch[][] generateSwitchesValue(int[] permutation){ + int n = permutation.length; + assert ((n & n-1) == 0); //n == 2^k + int layers = numberOfLayers(n); + + int[] pi, piL, piR; + Queue permutationsQueue = new ArrayBlockingQueue(n); + Graph graph; + int iDiv2; + int nDiv2 = n >> 1; + Switch[][] switches = new Switch[layers][nDiv2]; + int index1,index2; + + permutationsQueue.add(permutation); + for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size + { + iDiv2 = i >> 1; + for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation start index + { + pi = permutationsQueue.remove(); + graph = new Graph(pi); + piL = new int[iDiv2]; + piR = new int[iDiv2]; + for (int k = 0; k < iDiv2; k++){ // k == switch index in permutation j + + index1 = k + (j << 1); + index2 = index1 + iDiv2; + switches[layers - layer - 1][k + j] = new Switch(index1,index2,layers - layer - 1,graph.getSwitchValue(k, true)); + switches[layer][k + j] = new Switch(index1,index2,layer,graph.getSwitchValue(k, false)); + + if (!switches[layers - layer - 1][k + j].value) { + piL[k] = pi[k] % iDiv2; + piR[k] = pi[k + iDiv2] % iDiv2; + } else { + piL[k] = pi[k + iDiv2] % iDiv2; + piR[k] = pi[k] % iDiv2; + } + } + permutationsQueue.add(piL); + permutationsQueue.add(piR); + } + } + return switches; + } + + /** + * getter for switches value at layer + * @param layer + * @return switches[layer] + */ + public Switch[] getSwitchesByLayer(int layer) + { + return switches[layer]; + } + + /** + * calc number of layers for n values + * @param n number of votes + * @return layers + */ + public static int numberOfLayers(int n){ + return (int) (2 * Math.log(n) / Math.log(2)) - 1; + } + + /** + * inner class + * graph object, part of benes mix network algorithm + */ + private class Graph { + private int n; + private int nDiv2; + private Node[][] nodes; + protected Graph(int[] permutation){ + n = permutation.length; // n = 2^k + nDiv2 = n >> 1; + createNodes(); + createEdges(permutation); + setSwitches(); + } + + /** + * provide an access to algorithm result + * index must be less then n/2 + */ + protected boolean getSwitchValue(int index,boolean up) { + return up ? nodes[0][index].value : nodes[1][index].value; + } + + + + + + + /** + * create two lines of nodes size n/2 each + * the value of the i th node is (i,i+n/2) if i < n /2 (first line) + * otherwise its value is (i - n/2 , i) (second line) + */ + private void createNodes() { + nodes = new Node[2][nDiv2]; + for (int i = 0; i < nDiv2; i++) { + nodes[0][i] = new Node(); + nodes[1][i] = new Node(); + } + } + + /** create an edge between each pair of nodes i,j from different lines (i index of the first line) + * if exists k in i th node's value and t in j th node's value + * s.t permutation[k] == t + * the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2) + * Note: in purpose to avoid edge cases, each node has exactly two edges + */ + private void createEdges(int[] permutation) { + int j; + for (int i = 0; i < nDiv2; i++) { + j = permutation[i] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i] >= nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i] >= nDiv2))); + + j = permutation[i + nDiv2] % nDiv2; + nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i + nDiv2] < nDiv2))); + nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i + nDiv2] < nDiv2))); + } + } + + /** + * set switch's value (on/off) for each switch (node) + * s.t if nodes i,j connected by edge e, i th switch's value + * must be equal to j's if e is broken or not equal if e is not broken + */ + private void setSwitches() { + Node node; + boolean v; + Edge e0,e1; + // iterate over first line of nodes + for (int i = 0; i < nDiv2; i++) { + node = nodes[0][i]; + if (node.set) + continue; + //select default value for first node in connected component + v = false; + // set value to all reachable nodes from node + while (true) { + node.set = true; + node.value = v; + e0 = node.edges.get(0); e1 = node.edges.get(1); + if (e0.neighbor.set && e1.neighbor.set) + break; + v ^= (!e0.neighbor.set) ? e0.broken : e1.broken; + node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor; + } + } + } + + /** + * inner class + * node object in graph + * there are exactly twp edges for each node + */ + private class Node { + public List edges; + private boolean value; + private boolean set; + public Node() { + edges = new ArrayList(2); + set = false; + } + } + + /** + * inner class + * edge object in graph + */ + private class Edge { + public Node neighbor; + public boolean broken; + public Edge(Node neighbor, boolean broken) { + this.neighbor = neighbor; + this.broken = broken; + } + } + } + + } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java index c405784..fbe091c 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java @@ -1,7 +1,193 @@ package meerkat.mixer.mixing; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.Encryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto.EncryptionRandomness; +import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage; +import meerkat.protobuf.Mixing.ZeroKnowledgeProof; + +import java.util.List; +import java.util.Random; + /** - * Created by Tzlil on 4/16/2016. + * an implementation of meerkat.crypto.mixnet.Mixer + * meerkat.mixer.mixing algorithm on set of n encrypted votes: + * 0. asset n is power of two + * 1. set switches according to benes network on random permutation + * 2. re encrypt and mix with respect to switches values (encryptor.rerandomize) + * 3. generate zero knowledge proof on each re encrypted couple + * 4. return proofs table + encryption table + * */ -public class Mixer { -} +public class Mixer implements meerkat.crypto.mixnet.Mixer { + + private final Mix2ZeroKnowledgeProver prover; + private final Encryption encryptor; + + /** + * constructor + * @param prover + * @param encryptor + */ + public Mixer(Mix2ZeroKnowledgeProver prover, Encryption encryptor) { + this.prover = prover; + this.encryptor = encryptor; + } + + /** + * return True iff n == 2 ^ k + * @param n + * @return + */ + public static boolean isPowerOfTwo(int n){ + return (n & (n - 1)) == 0; + } + + /** + * initialize encryption table of size (layers + 1)* n + * @param n number of votes + * @param layers + * @param ciphertexts encrypted votes + * @return an initialized encryption table s.t first layer == given encrypted votes + */ + private RerandomizableEncryptedMessage[][] initializeEncryptionTable(int n,int layers,List ciphertexts){ + // set first level of encryption + RerandomizableEncryptedMessage[][] encryptionTable = new RerandomizableEncryptedMessage[layers + 1][n]; + for (int j = 0; j < n; j++) { + encryptionTable[0][j] = ciphertexts.get(j); + } + return encryptionTable; + } + + /** + * generate randomness for all rerandomize operations + * @param n number of votes + * @param layers + * @return an initialized randomness table of size layers * n + */ + private EncryptionRandomness[][] generateRandomnessesForRerandomize(int n,int layers,Random random){ + EncryptionRandomness[][] randomnesses = new EncryptionRandomness[layers][n]; + for (int layer = 0; layer < layers; layer++) + { + for (int i = 0; i < n; i++) { + randomnesses[layer][i] = encryptor.generateRandomness(random);; + } + } + return randomnesses; + } + + /** + * generate new random mix network + * @param n number of votes + * @param random + * @return new random mix network + */ + private MixNetwork generateMixNetwork(int n,Random random){ + return new MixNetwork(new RandomPermutation(n,random)); + } + + /** + * fills the encryption table with rerandomize encrypted votes. + * @param layers + * @param mixNetwork switches table (boolean values) + * @param encryptionTable an initialized encryption table s.t first layer == given encrypted votes + * @param randomnesses an initialized randomness table of size layers * n, use for rerandomize operations + * @throws InvalidProtocolBufferException + */ + private void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable + ,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + Switch[] switchesLayer; + int index1,index2; + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; + if (!sw.value) { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2); + + } else { + encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2); + encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1); + } + } + } + } + + /** + * generate zero knowledge proof for each rerandomize encrypted votes couple in encryptionTable + * @param n number of votes + * @param layers + * @param mixNetwork switches table (boolean values) used for set encryption table + * @param encryptionTable full encryption table + * @param randomnesses randomness table of size layers * n, used for set encryption table + * @return zero knowledge proofs table + * @throws InvalidProtocolBufferException + */ + private ZeroKnowledgeProof[][] generateZeroKnowledgeProofTable(int n, int layers, MixNetwork mixNetwork + , RerandomizableEncryptedMessage[][] encryptionTable + , EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { + Switch[] switchesLayer; + int index1,index2; + int switchIndex = 0; + int nDiv2 = n >> 1; + ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + + RerandomizableEncryptedMessage e1,e2; + EncryptionRandomness r1,r2; + for (int layer = 0; layer < layers; layer++) + { + switchesLayer = mixNetwork.getSwitchesByLayer(layer); + for (Switch sw : switchesLayer) { + index1 = sw.i; + index2 = sw.j; + e1 = encryptionTable[layer][index1]; + e2 = encryptionTable[layer][index2]; + r1 = randomnesses[layer][index1]; + r2 = randomnesses[layer][index2]; + + proofsTable[layer][switchIndex] = + prover.prove(e1, e2, encryptionTable[layer + 1][index1], + encryptionTable[layer + 1][index2], + sw.value, sw.i, sw.j, sw.layer, r1, r2); + + switchIndex = (switchIndex + 1) % nDiv2; + } + } + return proofsTable; + } + + /** + * mix given encrypted votes using random + * @param ciphertexts encrypted votes + * @param random + * @return meerkat.mixer.mixing result + * @throws InvalidProtocolBufferException + */ + public MixerOutput mix(List ciphertexts,Random random) throws InvalidProtocolBufferException { + + int n = ciphertexts.size(); + assert (n > 1 && isPowerOfTwo(n)); + + int layers = MixNetwork.numberOfLayers(n); // layers = 2logn -1 + RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts); + EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random); + MixNetwork mixNetwork = generateMixNetwork(n,random); + rerandomize(layers,mixNetwork,encryptionTable,randomnesses); + ZeroKnowledgeProof[][] proofsTable = generateZeroKnowledgeProofTable(n,layers,mixNetwork,encryptionTable,randomnesses); + + return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable); + } + +} \ No newline at end of file diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java index dbeac75..64636cc 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java @@ -1,7 +1,130 @@ package meerkat.mixer.mixing; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 1/18/2016. + * implements meerkat.crypto.mixnet.MixerOutput interface + * container for meerkat.mixer.mixing.mix result. */ -public class MixerOutput { +public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ + private final Mixing.ZeroKnowledgeProof[][] proofs; + private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; + private final int n; + private final int layers; + + /** + * constructor + * @param n number of votes + * @param layers + * @param encryptedMessages at level 0 , contains the original encrypted votes + * at each other level contains the re encrypted votes + * @param proofs in each cell (level,switch) contains the match zero knowledge proof + */ + public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs + , Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { + this.proofs = proofs; + this.encryptedMessages = encryptedMessages; + this.n = n; + this.layers = layers; + } + + + + @Override + public Mixing.ZeroKnowledgeProof[][] getProofs() { + return proofs; + } + + @Override + public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() { + return encryptedMessages; + } + + @Override + public int getN() { + return n; + } + + /** + * print the output, encrypted messages and proofs, to folder + * @param dir - directory + * @throws IOException + */ + public void outToFolder(String dir) throws IOException { + + (new File(dir)).mkdirs(); + //create files + String proofsDir = dir + "/Proofs"; + String encDir = dir + "/EncryptedMessages"; + (new File(proofsDir)).mkdir(); + (new File(encDir)).mkdir(); + for (int layer = 0; layer < layers; layer++){ + (new File(proofsDir +"/layer" + layer )).mkdir(); + (new File(encDir +"/layer" + layer )).mkdir(); + } + (new File(encDir +"/input")).mkdir(); + + + for (int layer = 0; layer < layers; layer++){ + for(int i = 0; i < proofs[layer].length; i ++){ + writeProofToFile(proofsDir,proofs[layer][i]); + } + } + + for (int layer = 0; layer <= layers; layer++){ + for(int i = 0; i < encryptedMessages[layer].length; i ++){ + writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]); + } + } + } + + /** + * create new file contains single proof + * @param proofsDir + * @param proof + * @throws IOException + */ + private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException { + Mixing.ZeroKnowledgeProof.Location location = proof.getLocation(); + int layer = location.getLayer(); + int i = location.getI(); + int j = location.getJ(); + String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(proof.toByteArray()); + fos.close(); + } + + /** + * create new file contains single encrypted message + * @param encDir + * @param layer + * @param i + * @param enc + * @throws IOException + */ + private void writeEncToFile(String encDir,int layer,int i, Crypto.RerandomizableEncryptedMessage enc) throws IOException { + + String fileName; + if(layer >= 0) + fileName = encDir+"/layer" + layer +"/" + i; + else + fileName = encDir+"/input/" + i; + + File file = new File(fileName); + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(enc.toByteArray()); + fos.close(); + } } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java index 9202403..7f18530 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/RandomPermutation.java @@ -1,7 +1,45 @@ package meerkat.mixer.mixing; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/17/2015. + * container for random permutation + * the permutation is sated in constructor and can't be change */ public class RandomPermutation { + public final int[] permutation; + + /** + * constructor + * @param n permutation size + * @param random + */ + public RandomPermutation(int n,Random random) { + this.permutation = generatePermutation(n,random); + } + + /** + * generate random permutation ovver [0,n) + * @param n permutation size + * @param random + * @return permutation + */ + private int[] generatePermutation(int n,Random random){ + List numbers= new ArrayList(n); + for (int i = 0; i < n; i++) { + numbers.add(i); + } + + int[] result = new int[n]; + int index; + for (int i = 0; i < n; i++) { + index = random.nextInt(n - i); + result[i] = numbers.get(index); + numbers.remove(index); + } + return result; + } } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Switch.java b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java index 0d9c17e..5de522e 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Switch.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Switch.java @@ -1,7 +1,36 @@ package meerkat.mixer.mixing; /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/15/2015. + * container for switch */ -public class Switch { +public class Switch{ + + public final int i, j, layer; + public final boolean value; + + /** + * constructor + * @param i + * @param j + * @param layer + * @param value the switch is on or off + */ + public Switch(int i, int j, int layer, boolean value) { + this.i = i; + this.j = j; + this.layer = layer; + this.value = value; + } + + + @Override + public String toString() { + return "Switch{" + + "i=" + i + + ", j=" + j + + ", layer=" + layer + + ", value=" + value + + '}'; + } } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java index 410bf54..d1a2d9f 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/AsyncBulletinBoardClient.java @@ -1,7 +1,80 @@ package meerkat.mixer.necessary; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * ToDo: this should be replaced by AsyncBulletinBoardClient at BB project */ -public class AsyncBulletinBoardClient { +public interface AsyncBulletinBoardClient extends BulletinBoardClient { + + public interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + public interface MessageHandler { + void handleNewMessages(List messageList); + } + + /** + * Post a message to the bulletin board in an asynchronous manner + * @param msg is the message to be posted + * @param callback is a class containing methods to handle the result of the operation + * @return a unique message ID for the message, that can be later used to retrieve the batch + */ + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + + /** + * This method allows for sending large messages as a batch to the bulletin board + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param batchDataList is the (canonically ordered) list of data comprising the batch message + * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) + * @param callback is a callback function class for handling results of the operation + * @return a unique message ID for the entire message, that can be later used to retrieve the batch + */ + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatch method in which startPosition is set to the default value 0 + */ + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + + /** + * Check how "safe" a given message is in an asynchronous manner + * The result of the computation is a rank between 0.0 and 1.0 indicating the fraction of servers containing the message + * @param id is the unique message identifier for retrieval + * @param callback is a callback function class for handling results of the operation + */ + public void getRedundancy(MessageID id, ClientCallback callback); + + /** + * Read all messages posted matching the given filter in an asynchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @param callback is a callback function class for handling results of the operation + */ + public void readMessages(MessageFilterList filterList, ClientCallback> callback); + + /** + * Read a given batch message from the bulletin board + * @param signerId is the ID of the signer (sender) of the batch message + * @param batchId is the unique (per signer) ID of the batch + * @param callback is a callback class for handling the result of the operation + */ + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * @param filterList defines the set of filters for message retrieval + * @param messageHandler defines the handler for new messages received + */ + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); + } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java index a4e0a0a..aebe469 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/BulletinBoardClient.java @@ -1,7 +1,61 @@ package meerkat.mixer.necessary; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.Voting.BulletinBoardClientParams; + +import java.util.List; + +import static meerkat.protobuf.BulletinBoardAPI.*; + /** - * Created by Tzlil on 4/16/2016. + * Created by talm on 24/10/15. + * + * ToDo: this should be replaced by BulletinBoardClient at BB project */ -public class BulletinBoardClient { +public interface BulletinBoardClient { + + interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + /** + * Initialize the client to use some specified servers + * @param clientParams contains the parameters required for the client setup + */ + void init(BulletinBoardClientParams clientParams); + + /** + * Post a message to the bulletin board in a synchronous manner + * @param msg is the message to be posted + * @return a unique message ID for the message, that can be later used to retrieve the batch + * @throws CommunicationException + */ + MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; + + + + /** + * Check how "safe" a given message is in a synchronous manner + * @param id is the unique message identifier for retrieval + * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) + */ + float getRedundancy(MessageID id); + + /** + * Read all messages posted matching the given filter in a synchronous manner + * Note that if messages haven't been "fully posted", this might return a different + * set of messages in different calls. However, messages that are fully posted + * are guaranteed to be included. + * @param filterList return only messages that match the filters (null means no filtering). + * @return the list of messages + */ + List readMessages(MessageFilterList filterList); + + /** + * Closes all connections, if any. + * This is msgRecived in a synchronous (blocking) way. + */ + void close(); + } diff --git a/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java index b8067e5..c93506e 100644 --- a/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java +++ b/mixer/src/main/java/meerkat/mixer/necessary/CompleteBatch.java @@ -1,7 +1,70 @@ package meerkat.mixer.necessary; + +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.*; + +import java.util.LinkedList; +import java.util.List; + /** - * Created by Tzlil on 4/16/2016. + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * A data structure for holding a complete batch message along with its signature + * + * ToDo: this should be replaced by CompleteBatch at BB project */ public class CompleteBatch { + + private BeginBatchMessage beginBatchMessage; + private List batchDataList; + private Signature signature; + + public CompleteBatch() { + batchDataList = new LinkedList(); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { + this(); + beginBatchMessage = newBeginBatchMessage; + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList) { + this(newBeginBatchMessage); + appendBatchData(newDataList); + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature) { + this(newBeginBatchMessage, newDataList); + signature = newSignature; + } + + public BeginBatchMessage getBeginBatchMessage() { + return beginBatchMessage; + } + + public List getBatchDataList() { + return batchDataList; + } + + public Signature getSignature() { + return signature; + } + + public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { + this.beginBatchMessage = beginBatchMessage; + } + + public void appendBatchData(BatchData newBatchData) { + batchDataList.add(newBatchData); + } + + public void appendBatchData(List newBatchDataList) { + batchDataList.addAll(newBatchDataList); + } + + public void setSignature(Signature newSignature) { + signature = newSignature; + } + } diff --git a/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java index 1d2272b..153dc12 100644 --- a/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java +++ b/mixer/src/main/java/meerkat/mixer/prover/ElGamalProofOrganizer.java @@ -1,7 +1,303 @@ package meerkat.mixer.prover; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; + /** - * Created by Tzlil on 4/16/2016. + * use for organize the input for each ZKP + * + * both meerkat.mixer.prover and meerkat.mixer.verifier implantation are using it */ public class ElGamalProofOrganizer { + + private final ECGroup group; + private final ECPoint g; + private final ECPoint h; + private final byte[] gEncoded; + private final byte[] hEncoded; + + /** + * @param group + * @param g - generator of group + * @param h - h = g ^ SecretKey + */ + public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){ + this.group = group; + this.g = g; + this.h = h; + this.gEncoded = group.encode(g); + this.hEncoded = group.encode(h); + } + + public enum OrProofOrder { + first, second, third, fourth + } + + public enum TrueCouple { + left, right, unknown + } + + /** + * can be used by meerkat.mixer.prover only + * + * call to the meerkat.mixer.main overload with flag = true + */ + protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException { + + //boolean flag = true; + return createProofInput(in1,in2,out1,out2,r1,r2,switched,true); + } + + /** + * can be used by anyone, e.g meerkat.mixer.verifier + * + * call to the meerkat.mixer.main overload with flag = false + */ + public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException { + + // flag = false; + return createProofInput(in1,in2,out1,out2,null,null,false,false); + } + + /** + * inner method + * convert each encrypted message to ElGamalCiphertext + * + * @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known) + * @return ElGamalProofInput + * @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't + * ElGamalCiphertext + */ + private ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2 + , Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2 + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag) + throws InvalidProtocolBufferException { + + //convert RerandomizableEncryptedMessage to ElGamalCiphertext + ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1); + ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2); + ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1); + ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2); + + if(flag) { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched); + }else { + return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal); + } + } + + + /** + * can be construct by instance of organizer only by calling createProofInput method (all constructors are private) + * + * in construction it use for preparing the input for prove, while avoiding double converting or calculations + * + * use as a container for 4 OrProofInput. + */ + public class ElGamalProofInput { + + private final OrProofInput first; + private final OrProofInput second; + private final OrProofInput third; + private final OrProofInput fourth; + + private ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + + /** + * @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known) + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag){ + + ECPoint e1c1 = convert2ECPoint(e1.getC1()); + ECPoint e1c2 = convert2ECPoint(e1.getC2()); + ECPoint e2c1 = convert2ECPoint(e2.getC1()); + ECPoint e2c2 = convert2ECPoint(e2.getC2()); + ECPoint e1Nc1 = convert2ECPoint(e1New.getC1()); + ECPoint e1Nc2 = convert2ECPoint(e1New.getC2()); + ECPoint e2Nc1 = convert2ECPoint(e2New.getC1()); + ECPoint e2Nc2 = convert2ECPoint(e2New.getC2()); + + ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); + ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); + ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1)); + ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1)); + + ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2)); + ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2)); + ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2)); + ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2)); + + + if(!flag){ + + this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2); + this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1); + this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2); + this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2); + + }else { + + byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); + byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); + byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); + byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); + byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); + byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); + byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); + byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); + + + if (!switched) { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r1, TrueCouple.left); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.left); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.right); + } else { + this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded + , r2, TrueCouple.right); + this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1 + , c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded + , r1, TrueCouple.right); + this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2 + , c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r2, TrueCouple.left); + this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2 + , c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded + , r1, TrueCouple.left); + } + } + } + + + /** + * used by the meerkat.mixer.prover + * call to the meerkat.mixer.main constructor with flag = true + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New + , Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){ + //flag = true; + this(e1,e2,e1New,e2New,r1,r2,switched,true); + } + + /** + * used by meerkat.mixer.prover + * call to the meerkat.mixer.main constructor with flag = true + */ + private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 + , ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ + //flag = false; + this(e1,e2,e1New,e2New,null,null,false,false); + } + + /** + * getter for all 4 OrProofInputs + * + * @param orProofOrder + * @return the required OrProof + */ + public OrProofInput getOrProofInput(OrProofOrder orProofOrder) { + switch (orProofOrder) { + + case first: + return this.first; + case second: + return this.second; + case third: + return this.third; + case fourth: + return this.fourth; + } + return null; + } + } + + + /** + * can't be constructed (all constructors are private) + * + * 4 instances will be constructed for each new ElGamalProofInput + * + * container for all meerkat.mixer.necessary inputs for single OrProof + */ + public class OrProofInput{ + public final ECPoint g1; + public final ECPoint h1; + public final ECPoint g2; + public final ECPoint h2; + public final ECPoint g1Tag; + public final ECPoint h1Tag; + public final ECPoint g2Tag; + public final ECPoint h2Tag; + + // can be access by meerkat.mixer.prover only + protected final byte[] g1Encoded; + protected final byte[] h1Encoded; + protected final byte[] g2Encoded; + protected final byte[] h2Encoded; + protected final byte[] g1TagEncoded; + protected final byte[] h1TagEncoded; + protected final byte[] g2TagEncoded; + protected final byte[] h2TagEncoded; + protected final Crypto.EncryptionRandomness x; + protected final TrueCouple flag; + + /** + * used by meerkat.mixer.prover only + */ + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag + ,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded + , Crypto.EncryptionRandomness x, TrueCouple flag) { + this.g1 = g; + this.h1 = h1; + this.g2 = h; + this.h2 = h2; + this.g1Tag = g; + this.h1Tag = h1Tag; + this.g2Tag = h; + this.h2Tag = h2Tag; + + this.g1Encoded = gEncoded; + this.h1Encoded = h1Encoded; + this.g2Encoded = hEncoded; + this.h2Encoded = h2Encoded; + this.g1TagEncoded = gEncoded; + this.h1TagEncoded = h1TagEncoded; + this.g2TagEncoded = hEncoded; + this.h2TagEncoded = h2TagEncoded; + + this.x = x; + this.flag = flag; + + } + + /** + * used by meerkat.mixer.verifier + */ + private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) { + this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown); + } + } } diff --git a/mixer/src/main/java/meerkat/mixer/prover/Prover.java b/mixer/src/main/java/meerkat/mixer/prover/Prover.java index 9bda892..303c560 100644 --- a/mixer/src/main/java/meerkat/mixer/prover/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/prover/Prover.java @@ -1,7 +1,216 @@ package meerkat.mixer.prover; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; +import java.util.Random; + + /** - * Created by Tzlil on 4/16/2016. + * implements of Mix2ZeroKnowledgeProver interface + * this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext */ -public class Prover { +public class Prover implements Mix2ZeroKnowledgeProver { + + private final ECGroup group; + private final RandomOracle randomOracle; + private final Random rand; + private final ECElGamalEncryption encryptor; + private final ECPoint g,h; + private final BigInteger groupOrderUpperBound; + private final ElGamalProofOrganizer organizer; + + /** + * @param rand + * @param encryptor + * @param randomOracle - use for Fiat–Shamir heuristic + */ + public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { + + this.rand = rand; + this.encryptor = encryptor; + this.randomOracle = randomOracle; + this.group = this.encryptor.getGroup(); + this.g = group.getGenerator(); + this.h = this.encryptor.getElGamalPK().getPK(); + this.organizer = new ElGamalProofOrganizer(group,g,h); + this.groupOrderUpperBound = group.orderUpperBound(); + } + + /** + * @param in1 + * @param in2 + * @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1) + * @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2) + * @param sw - flag + * @param i - column of in1 and out1 in encryption table + * @param j - column of in2 and out2 in encryption table + * @param layer - row of in1,in2 in encryption table + * @param r1 + * @param r2 + * @return - a valid ZKP that indeed out1,out2 calculated as required + * @throws InvalidProtocolBufferException + */ + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean sw,int i,int j, int layer, + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { + Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; + + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw); + + first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first)); + second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second)); + third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third)); + fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth)); + + Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() + .setI(i) + .setJ(j) + .setLayer(layer) + .build(); + + Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() + .setFirst(first) + .setSecond(second) + .setThird(third) + .setFourth(fourth) + .setLocation(location) + .build(); + return result; + } + + + /** + * Fiat–Shamir heuristic + * @param input - protobuf contains all parameters from the first step of the current prove + * @param randomOracle + * @return randomOracle.hash(input) + */ + public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input, RandomOracle randomOracle) { + byte[] arr = input.toByteArray(); + return new BigInteger(1,randomOracle.hash(arr,arr.length)); + } + + + /** + * @param orProofInput + * @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2) + * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.prover + */ + private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) { + + ECPoint g1 = orProofInput.g1; + ECPoint h1 = orProofInput.h1; + ECPoint g2 = orProofInput.g2; + ECPoint h2 = orProofInput.h2; + + ECPoint g1Tag = orProofInput.g1Tag; + ECPoint h1Tag = orProofInput.h1Tag; + ECPoint g2Tag = orProofInput.g2Tag; + ECPoint h2Tag = orProofInput.h2Tag; + + BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + BigInteger c1,c2,z,zTag; + ECPoint u,v,uTag,vTag; + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + + switch (orProofInput.flag) { + case left: + c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + //step 1 + u = group.multiply(g1, r); + v = group.multiply(g2, r); + uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); + vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); + //step 2 + // c1 = (hash(input + step1) + group size - c2)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c1 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); + //step 3 + //z = (r + c1 * x) % group size; + z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); + break; + case right: + c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); + //step 1 + uTag = group.multiply(g1Tag, r); + vTag = group.multiply(g2Tag, r); + u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); + v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); + //step 2 + // c1 = (hash(input + step1) + group size - c1)% group size + forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(ByteString.copyFrom(orProofInput.g1Encoded)) + .setH1(ByteString.copyFrom(orProofInput.h1Encoded)) + .setG2(ByteString.copyFrom(orProofInput.g2Encoded)) + .setH2(ByteString.copyFrom(orProofInput.h2Encoded)) + .setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded)) + .setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded)) + .setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded)) + .setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded)) + .setU(ByteString.copyFrom(group.encode(u))) + .setV(ByteString.copyFrom(group.encode(v))) + .setUTag(ByteString.copyFrom(group.encode(uTag))) + .setVTag(ByteString.copyFrom(group.encode(vTag))) + .build(); + c2 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); + //step 3 + //zTag = (r + c2 * x) % group size; + zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound); + break; + default: + return null; + } + + + return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() + .setG1(forRandomOracle.getG1()) + .setH1(forRandomOracle.getH1()) + .setG2(forRandomOracle.getG2()) + .setH2(forRandomOracle.getH2()) + .setG1Tag(forRandomOracle.getG1()) + .setH1Tag(forRandomOracle.getH1Tag()) + .setG2Tag(forRandomOracle.getG2Tag()) + .setH2Tag(forRandomOracle.getH2Tag()) + .setU(forRandomOracle.getU()) + .setV(forRandomOracle.getV()) + .setUTag(forRandomOracle.getUTag()) + .setVTag(forRandomOracle.getVTag()) + .setC1(ByteString.copyFrom(c1.toByteArray())) + .setC2(ByteString.copyFrom(c2.toByteArray())) + .setZ(ByteString.copyFrom(z.toByteArray())) + .setZTag(ByteString.copyFrom(zTag.toByteArray())) + .build(); + } } + diff --git a/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java index 0b19faa..ed08512 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/Verifier.java @@ -1,7 +1,95 @@ package meerkat.mixer.verifier; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import meerkat.mixer.prover.ElGamalProofOrganizer; +import meerkat.mixer.prover.Prover; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.primitives.concrete.ECGroup; + /** - * Created by Tzlil on 4/16/2016. + * implements Mix2ZeroKnowledgeVerifier */ -public class Verifier { +public class Verifier implements Mix2ZeroKnowledgeVerifier { + + + private final ECGroup group; + private final RandomOracle randomOracle; + private final ECPoint g,h; + private final ElGamalProofOrganizer organizer; + private final ZeroKnowledgeOrProofParser parser; + + /** + * constructor + * @param encryptor should be as the encryptor used by meerkat.mixer.prover + * @param randomOracle should be as the random oracle used by meerkat.mixer.prover + */ + public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) { + this.group = encryptor.getGroup(); + this.g = group.getGenerator(); + this.h = encryptor.getElGamalPK().getPK(); + this.randomOracle = randomOracle; + this.organizer = new ElGamalProofOrganizer(group,g,h); + this.parser = new ZeroKnowledgeOrProofParser(group); + } + + /** + * verify zero knowledge proof + * @param in1 + * @param in2 + * @param out1 + * @param out2 + * @param proof out1 = rerandomize(in1) && out2 = rerandomize(in2) + * || + * out1 = rerandomize(in2) && out2 = rerandomize(in1) + * @return true iff all 4 or proofs are valid + * @throws InvalidProtocolBufferException + */ + public boolean verify(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { + ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2); + return verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first), proof.getFirst())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second), proof.getSecond())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third), proof.getThird())&& + verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth), proof.getFourth()); + + } + + + /** + * + * @param orProofInput + * @param orProof + * @return verify single or proof + */ + private boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput, + Mixing.ZeroKnowledgeProof.OrProof orProof) { + ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof); + return container.g1.equals(orProofInput.g1) && + container.h1.equals(orProofInput.h1) && + container.g2.equals(orProofInput.g2) && + container.h2.equals(orProofInput.h2) && + container.g1Tag.equals(orProofInput.g1Tag) && + container.h1Tag.equals(orProofInput.h1Tag) && + container.g2Tag.equals(orProofInput.g2Tag) && + container.h2Tag.equals(orProofInput.h2Tag) && + container.c1.add(container.c2).mod(group.orderUpperBound()) + .equals(Prover.hash(container.forRandomOracle,randomOracle).mod(group.orderUpperBound())) && + group.multiply(container.g1, container.z) + .equals(group.add(container.u, group.multiply(container.h1,container.c1))) && + group.multiply(container.g2, container.z) + .equals(group.add(container.v, group.multiply(container.h2,container.c1))) && + group.multiply(container.g1Tag, container.zTag) + .equals(group.add(container.uTag, group.multiply(container.h1Tag,container.c2))) && + group.multiply(container.g2Tag, container.zTag) + .equals(group.add(container.vTag, group.multiply(container.h2Tag,container.c2))); + + } } diff --git a/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java index 1158e2e..2bb3781 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/VerifyTable.java @@ -1,7 +1,91 @@ package meerkat.mixer.verifier; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.crypto.mixnet.MixerOutput; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +import java.util.Arrays; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 12/30/2015. + * provide one operation - verify meerkat.mixer.mixing output */ -public class VerifyTable { +public final class VerifyTable { + /** + * constructor + * @param verifier + * @param n + * @param mixerOutput + * @return true iff the meerkat.mixer.mixing output is valid + * @throws InvalidProtocolBufferException + */ + public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput) + throws InvalidProtocolBufferException { + int index1,index2,layer; + + //assert n = 2^k + if ( (n &(n-1)) != 0) + throw new IllegalArgumentException("n"); + + int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1; + //initialize locationChecksum table + // use for check BeneshNet validity + boolean[][] locationChecksum = new boolean[layers][n]; + for (boolean[] locationChecksumLayer: locationChecksum) { + Arrays.fill(locationChecksumLayer,false); + } + + Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs(); + Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); + + for (int i = 0; i < zeroKnowledgeProofs.length ; i++){ + for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){ + Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j]; + Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + index1 = location.getI(); + index2 = location.getJ(); + layer = location.getLayer(); + + // check location validity + if (layer > layers >> 1) { + if (index2 - index1 != n >> (layers - layer)) + return false; + } + else{ + if (index2 - index1 != n >> (layer + 1)) + return false; + } + + // mark location in table + locationChecksum[layer][index1] = true; + locationChecksum[layer][index2] = true; + + // verify proof + if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp)) { + + verifier.verify(rerandomizableEncryptedMessages[layer][index1], + rerandomizableEncryptedMessages[layer][index2], + rerandomizableEncryptedMessages[layer + 1][index1], + rerandomizableEncryptedMessages[layer + 1][index2], + zkp); + return false; + } + } + } + + // verify all meerkat.mixer.necessary locations for BeneshNet were proved + for (boolean[] checksumLayer: locationChecksum) { + for (boolean locationBoolean: checksumLayer) { + if (!locationBoolean) + return false; + } + } + return true; + } } diff --git a/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java index 44fe45d..01ff344 100644 --- a/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java +++ b/mixer/src/main/java/meerkat/mixer/verifier/ZeroKnowledgeOrProofParser.java @@ -1,7 +1,95 @@ package meerkat.mixer.verifier; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; + /** - * Created by Tzlil on 4/16/2016. + * Created by Tzlil on 1/25/2016. + * zero knowledge proof parser */ public class ZeroKnowledgeOrProofParser { + + private final ECGroup group; + + /** + * parse or proof message and return the result in zero knowledge or proof container + * @param orProof + * @return zero knowledge or proof container + */ + public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ + return new ZeroKnowledgeOrProofContainer(orProof); + } + + /** + * getter + * @param group + */ + public ZeroKnowledgeOrProofParser(ECGroup group) { + this.group = group; + } + + /** + * convert ByteString to ECPoint + * @param bs + * @return + */ + public ECPoint convert2ECPoint(ByteString bs){ + return group.decode(bs.toByteArray()); + } + + + /** + * inner class + * container for parsed zero knowledge or proof + * constructor is private, can be construct using ZeroKnowledgeOrProofParser.parseOrProof + */ + public class ZeroKnowledgeOrProofContainer{ + public final ECPoint g1,g2,h1,h2; + public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; + public final ECPoint u,v,uTag,vTag; + public final BigInteger c1,c2,z,zTag; + public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; + + /** + * constructor + * @param orProof + */ + private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ + this.forRandomOracle = + Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() + .setG1(orProof.getG1()) + .setH1(orProof.getH1()) + .setG2(orProof.getG2()) + .setH2(orProof.getH2()) + .setG1Tag(orProof.getG1Tag()) + .setH1Tag(orProof.getH1Tag()) + .setG2Tag(orProof.getG2Tag()) + .setH2Tag(orProof.getH2Tag()) + .setU(orProof.getU()) + .setV(orProof.getV()) + .setUTag(orProof.getUTag()) + .setVTag(orProof.getVTag()) + .build(); + this.g1 = convert2ECPoint(orProof.getG1()); + this.g2 = convert2ECPoint(orProof.getG2()); + this.h1 = convert2ECPoint(orProof.getH1()); + this.h2 = convert2ECPoint(orProof.getH2()); + this.g1Tag = convert2ECPoint(orProof.getG1Tag()); + this.g2Tag = convert2ECPoint(orProof.getG2Tag()); + this.h1Tag = convert2ECPoint(orProof.getH1Tag()); + this.h2Tag = convert2ECPoint(orProof.getH2Tag()); + this.u = convert2ECPoint(orProof.getU()); + this.v = convert2ECPoint(orProof.getV()); + this.uTag = convert2ECPoint(orProof.getUTag()); + this.vTag = convert2ECPoint(orProof.getVTag()); + this.c1 = new BigInteger(orProof.getC1().toByteArray()); + this.c2 = new BigInteger(orProof.getC2().toByteArray()); + this.z = new BigInteger(orProof.getZ().toByteArray()); + this.zTag = new BigInteger(orProof.getZTag().toByteArray()); + } + } } diff --git a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java index 69a1637..fe45e1b 100644 --- a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java +++ b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java @@ -3,19 +3,18 @@ package meerkat.mixer; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.mixing.Mixer; +import meerkat.mixer.mixing.MixerOutput; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; +import meerkat.mixer.verifier.VerifyTable; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Mixer; -import mixer.MixerOutput; -import mixer.Utils; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; -import prover.Prover; -import verifier.Verifier; -import verifier.VerifyTable; import java.io.IOException; import java.security.spec.InvalidKeySpecException; @@ -52,7 +51,7 @@ public class CreateTestVector { randomOracle = new DigestOracle(); verifier = new Verifier(encryptor,randomOracle); prover = new Prover(randomProver,encryptor,randomOracle); - mixer = new Mixer(randomMixer,prover,encryptor,verifier); + mixer = new Mixer(prover,encryptor); // generate n int logN = 10; // + random.nextInt(8) @@ -74,11 +73,11 @@ public class CreateTestVector { List mixerInput = generateMixerInput(); System.out.println("start mixing"); - MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer); System.out.println("mixing ended, start verification"); assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); System.out.println("verification ended, start printing"); - mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); + mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3"); System.out.println("all done"); } @@ -91,11 +90,11 @@ public class CreateTestVector { List mixerInput = generateMixerInput(); System.out.println("start mixing"); - MixerOutput mixerOutput = new MixerOutput(mixer.mix(mixerInput)); + MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random); System.out.println("mixing ended, start negative verification"); assert (!VerifyTable.verifyTable(verifier,n,mixerOutput)); System.out.println("verification ended, start printing"); - mixerOutput.outToFile("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); + mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5"); System.out.println("all done"); } } diff --git a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java index 7755fd4..23eaea4 100644 --- a/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixNetworkTest.java @@ -4,6 +4,9 @@ package meerkat.mixer; * Created by Tzlil on 12/17/2015. */ +import meerkat.mixer.mixing.MixNetwork; +import meerkat.mixer.mixing.RandomPermutation; +import meerkat.mixer.mixing.Switch; import org.junit.Test; import java.util.Arrays; import java.util.Random; diff --git a/mixer/src/test/java/meerkat/mixer/MixingTest.java b/mixer/src/test/java/meerkat/mixer/MixingTest.java index 626060f..f9ec6f8 100644 --- a/mixer/src/test/java/meerkat/mixer/MixingTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixingTest.java @@ -7,6 +7,10 @@ package meerkat.mixer; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.mixing.Mixer; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; +import meerkat.mixer.verifier.VerifyTable; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; import org.factcenter.qilin.primitives.RandomOracle; @@ -15,9 +19,6 @@ import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; -import prover.Prover; -import verifier.Verifier; -import verifier.VerifyTable; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; @@ -49,7 +50,7 @@ public class MixingTest { randomOracle = new DigestOracle(); verifier = new Verifier(encryptor,randomOracle); prover = new Prover(randomProver,encryptor,randomOracle); - mixer = new Mixer(randomMixer,prover,encryptor); + mixer = new Mixer(prover,encryptor); // generate n int logN = 8; // + random.nextInt(8) @@ -75,7 +76,7 @@ public class MixingTest { System.out.println(" start mixing"); long startTime = System.currentTimeMillis(); - meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput); + meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput,randomMixer); long finishTime = System.currentTimeMillis(); System.out.println(" that took: "+(finishTime-startTime)+ " ms"); diff --git a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java index a87d043..cb7ea3f 100644 --- a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java @@ -5,6 +5,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.prover.Prover; +import meerkat.mixer.verifier.Verifier; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; @@ -15,8 +17,6 @@ import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; import org.junit.Before; import org.junit.Test; -import prover.Prover; -import verifier.Verifier; import java.math.BigInteger; import java.util.Random; diff --git a/mixer/src/test/java/profiling/BigInteger/AddSub.java b/mixer/src/test/java/profiling/BigInteger/AddSub.java index 19474f7..8e3b5c1 100644 --- a/mixer/src/test/java/profiling/BigInteger/AddSub.java +++ b/mixer/src/test/java/profiling/BigInteger/AddSub.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java index e003dea..ebe80f0 100644 --- a/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java +++ b/mixer/src/test/java/profiling/BigInteger/GenerateRandomness.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/Modulo.java b/mixer/src/test/java/profiling/BigInteger/Modulo.java index 9443347..d0149b0 100644 --- a/mixer/src/test/java/profiling/BigInteger/Modulo.java +++ b/mixer/src/test/java/profiling/BigInteger/Modulo.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/BigInteger/Mul.java b/mixer/src/test/java/profiling/BigInteger/Mul.java index dfb8090..4ac913a 100644 --- a/mixer/src/test/java/profiling/BigInteger/Mul.java +++ b/mixer/src/test/java/profiling/BigInteger/Mul.java @@ -3,7 +3,7 @@ package profiling.BigInteger; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index 92b0c3f..f9b5b2e 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -5,7 +5,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java index 3473430..3d7435f 100644 --- a/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java +++ b/mixer/src/test/java/profiling/Convert/RerandomizableEncryptedMessage2ElGamalCiphertext.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Add.java b/mixer/src/test/java/profiling/ECGroup/Add.java index a1cbdfb..e0b5406 100644 --- a/mixer/src/test/java/profiling/ECGroup/Add.java +++ b/mixer/src/test/java/profiling/ECGroup/Add.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Encode.java b/mixer/src/test/java/profiling/ECGroup/Encode.java index d9577d7..59201e3 100644 --- a/mixer/src/test/java/profiling/ECGroup/Encode.java +++ b/mixer/src/test/java/profiling/ECGroup/Encode.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Mul.java b/mixer/src/test/java/profiling/ECGroup/Mul.java index 2a5573a..836db0e 100644 --- a/mixer/src/test/java/profiling/ECGroup/Mul.java +++ b/mixer/src/test/java/profiling/ECGroup/Mul.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ECGroup/Negate.java b/mixer/src/test/java/profiling/ECGroup/Negate.java index f5b6e15..d190186 100644 --- a/mixer/src/test/java/profiling/ECGroup/Negate.java +++ b/mixer/src/test/java/profiling/ECGroup/Negate.java @@ -2,7 +2,7 @@ package profiling.ECGroup; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/Rerandomize.java b/mixer/src/test/java/profiling/Rerandomize.java index ea900b5..5a113c9 100644 --- a/mixer/src/test/java/profiling/Rerandomize.java +++ b/mixer/src/test/java/profiling/Rerandomize.java @@ -5,7 +5,7 @@ import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; diff --git a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java index fe1d407..7d38bf1 100644 --- a/mixer/src/test/java/profiling/ZeroKnowledgeProof.java +++ b/mixer/src/test/java/profiling/ZeroKnowledgeProof.java @@ -4,16 +4,16 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.mixer.prover.Prover; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting; -import mixer.Utils; +import meerkat.mixer.Utils; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECGroup; -import prover.Prover; import java.math.BigInteger; import java.util.Random;