mixer
tzlil.gon 2016-04-17 09:08:21 +03:00
parent f5410bedf4
commit b4e5040814
38 changed files with 115 additions and 1766 deletions

View File

@ -1,91 +0,0 @@
package 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.
*/
public class BatchConverter {
private final int n,layers;
public BatchConverter(int n,int layers){
this.n = n;
this.layers = layers;
}
private ByteString Integer2ByteString(int a){
return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray());
}
private int ByteString2Integer(ByteString bs) {
return Integer.valueOf(bs.toString());
}
public List<BulletinBoardAPI.BatchData> MixerOutput2BatchData(MixerOutput mixerOutput) {
List<BulletinBoardAPI.BatchData> result = new ArrayList<BulletinBoardAPI.BatchData>();
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;
}
public MixerOutput BatchDataList2MixerOutput
(List<BulletinBoardAPI.BatchData> 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 mixer.MixerOutput(n,layers,proofs,encryptions);
}
}

View File

@ -1,77 +0,0 @@
package main;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
import meerkat.crypto.mixnet.MixerOutput;
import meerkat.protobuf.Crypto;
import necessary.AsyncBulletinBoardClient;
import necessary.CompleteBatch;
import verifier.VerifyTable;
import java.util.Arrays;
import java.util.List;
/**
* Created by Tzlil on 12/17/2015.
*/
public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch> {
private MixerOutput mixerOutput;
private boolean msgReceived;
private Throwable t;
private CompleteBatch msg;
private final int n, layers;
private final Mix2ZeroKnowledgeVerifier 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;
this.msgReceived = true;
}
@Override
public void handleFailure(Throwable t) {
this.t = t;
this.msgReceived = true;
}
public boolean isMsgReceived() {
return msgReceived;
}
private void convertMessage() throws Exception {
BatchConverter batchConverter = new BatchConverter(n,layers);
mixerOutput = batchConverter.BatchDataList2MixerOutput(msg.getBatchDataList());
}
public boolean verifyTable() throws Exception {
if (mixerOutput == null) {
convertMessage();
}
return VerifyTable.verifyTable(verifier, n, mixerOutput);
}
public List<Crypto.RerandomizableEncryptedMessage> getInputForMixer() throws Throwable {
if (t != null) {
throw t;
}
if (mixerOutput == null) {
convertMessage();
if (!VerifyTable.verifyTable(verifier, n, mixerOutput)) {
throw new Exception("in valid table");
}
}
return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1
}
}

View File

@ -1,95 +0,0 @@
package 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 necessary.AsyncBulletinBoardClient;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Tzlil on 12/17/2015.
*/
public class MainMixing {
private final Mixer mixer;
private final Mix2ZeroKnowledgeVerifier verifier;
private final int n, layers;
private final AsyncBulletinBoardClient asyncBulletinBoardClient;
private final byte[] id;
private final int mixerOrder;
public MainMixing(Mixer mixer, int mixerOrder, Mix2ZeroKnowledgeVerifier verifier, int n
, AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
this.mixer = mixer;
this.mixerOrder = mixerOrder;
this.verifier = verifier;
this.n = n;
this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1
this.asyncBulletinBoardClient = asyncBulletinBoardClient;
this.id = id;
}
public void main(List<Integer> prevBatchIds, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) throws Throwable {
List<Crypto.RerandomizableEncryptedMessage> mixerInput;
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
BatchHandler currentBatchHandler;
for (Integer prevBatchId : prevBatchIds) {
currentBatchHandler = new BatchHandler(n, layers,verifier);
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
batchHandlers.add(currentBatchHandler);
}
// ToDo : assert table continues
// ToDo : assert signature validity
boolean allDone = false;
while (!allDone) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// do nothing
}
// check all handlers messages were received
allDone = true;
for (BatchHandler batchHandler : batchHandlers) {
allDone &= batchHandler.isMsgReceived();
}
}
// 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);
updateBB(mixerOutput, batchId, callback);
}
private void updateBB(MixerOutput mixerOutput
, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) {
BatchConverter batchConverter = new BatchConverter(n,layers);
List<BulletinBoardAPI.BatchData> batchDataList = batchConverter.MixerOutput2BatchData(mixerOutput);
asyncBulletinBoardClient.postBatch(id, batchId, batchDataList, callback);
}
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.main;
/**
* Created by Tzlil on 4/16/2016.
*/
public class BatchHandler {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.main;
/**
* Created by Tzlil on 4/16/2016.
*/
public class MainMixing {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.mixing;
/**
* Created by Tzlil on 4/16/2016.
*/
public class MixNetwork {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.mixing;
/**
* Created by Tzlil on 4/16/2016.
*/
public class Mixer {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.mixing;
/**
* Created by Tzlil on 4/16/2016.
*/
public class MixerOutput {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.mixing;
/**
* Created by Tzlil on 4/16/2016.
*/
public class RandomPermutation {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.mixing;
/**
* Created by Tzlil on 4/16/2016.
*/
public class Switch {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.necessary;
/**
* Created by Tzlil on 4/16/2016.
*/
public class AsyncBulletinBoardClient {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.necessary;
/**
* Created by Tzlil on 4/16/2016.
*/
public class BulletinBoardClient {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.necessary;
/**
* Created by Tzlil on 4/16/2016.
*/
public class CompleteBatch {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.prover;
/**
* Created by Tzlil on 4/16/2016.
*/
public class ElGamalProofOrganizer {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.prover;
/**
* Created by Tzlil on 4/16/2016.
*/
public class Prover {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.verifier;
/**
* Created by Tzlil on 4/16/2016.
*/
public class Verifier {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.verifier;
/**
* Created by Tzlil on 4/16/2016.
*/
public class VerifyTable {
}

View File

@ -0,0 +1,7 @@
package meerkat.mixer.verifier;
/**
* Created by Tzlil on 4/16/2016.
*/
public class ZeroKnowledgeOrProofParser {
}

View File

@ -1,175 +0,0 @@
package mixer;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.Random;
/**
* Created by Tzlil on 12/15/2015.
*/
public class MixNetwork {
private final Switch[][] switches;
public MixNetwork(RandomPermutation randomPermutation)
{
int[] permutation = randomPermutation.permutation;
int n = permutation.length;
assert ((n & n-1) == 0); //n == 2^k
int layers = (int)(2*Math.log(n)/Math.log(2)) - 1;
int[] pi, piL, piR;
Queue<int[]> permutationsQueue = new ArrayBlockingQueue<int[]>(n);
Graph graph;
int iDiv2;
int nDiv2 = n >> 1;
switches = new Switch[layers][nDiv2];
int index1,index2;
permutationsQueue.add(permutation);
for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size
{
iDiv2 = i >> 1;
for (int j = 0; j < nDiv2; j += iDiv2) // j == permutation start index
{
pi = permutationsQueue.remove();
graph = new Graph(pi);
piL = new int[iDiv2];
piR = new int[iDiv2];
for (int k = 0; k < iDiv2; k++) // k == switch index in permutation j
{
index1 = k + (j << 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);
}
}
}
public Switch[] getSwitchesByLayer(int layer)
{
return switches[layer];
}
private class Graph {
private int n;
private int nDiv2;
private Node[][] nodes;
protected Graph(int[] permutation){
n = permutation.length; // n = 2^k
nDiv2 = n >> 1;
createNodes();
createEdges(permutation);
setSwitches();
}
// provide an access to algorithm result
// index must be less then n/2
protected boolean getSwitchValue(int index,boolean up)
{
return up ? nodes[0][index].value : nodes[1][index].value;
}
// create two lines of nodes size n/2 each
// the value of the i th node is (i,i+n/2) if i < n /2 (first line)
// otherwise its value is (i - n/2 , i) (second line)
private void createNodes()
{
nodes = new Node[2][nDiv2];
for (int i = 0; i < nDiv2; i++)
{
nodes[0][i] = new Node();
nodes[1][i] = new Node();
}
}
// create an edge between each pair of nodes i,j from different lines (i index of the first line)
// if exists k in i th node's value and t in j th node's value
// s.t permutation[k] == t
// the edge is broken if (k < n/2 and t >= n/2) or (k >= n/2 and t < n/2)
// Note: in purpose to avoid edge cases, each node has exactly two edges
private void createEdges(int[] permutation)
{
int j;
for (int i = 0; i < nDiv2; i++)
{
j = permutation[i] % nDiv2;
nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i] >= nDiv2)));
nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i] >= nDiv2)));
j = permutation[i + nDiv2] % nDiv2;
nodes[0][i].edges.add(new Edge(nodes[1][j], (permutation[i + nDiv2] < nDiv2)));
nodes[1][j].edges.add(new Edge(nodes[0][i], (permutation[i + nDiv2] < nDiv2)));
}
}
// set switch's value (on/off) for each switch (node)
// s.t if nodes i,j connected by edge e, i th switch's value
// must be equal to j's if e is broken or not equal if e is not broken
private void setSwitches()
{
Node node;
boolean v;
Edge e0,e1;
// iterate over first line of nodes
for (int i = 0; i < nDiv2; i++)
{
node = nodes[0][i];
if (node.set)
continue;
//select default value for first node in connected component
v = false;
// set value to all reachable nodes from node
while (true)
{
node.set = true;
node.value = v;
e0 = node.edges.get(0); e1 = node.edges.get(1);
if (e0.neighbor.set && e1.neighbor.set)
break;
v ^= (!e0.neighbor.set) ? e0.broken : e1.broken;
node = (!e0.neighbor.set) ? e0.neighbor : e1.neighbor;
}
}
}
//inner classes
private class Node
{
public List<Edge> edges;
private boolean value;
private boolean set;
public Node()
{
edges = new ArrayList<Edge>(2);
set = false;
}
}
private class Edge
{
public Node neighbor;
public boolean broken;
public Edge(Node neighbor, boolean broken)
{
this.neighbor = neighbor;
this.broken = broken;
}
}
}
}

View File

@ -1,150 +0,0 @@
package mixer;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.Encryption;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
import meerkat.crypto.mixnet.MixerOutput;
import meerkat.protobuf.Crypto.EncryptionRandomness;
import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage;
import meerkat.protobuf.Mixing.ZeroKnowledgeProof;
import java.math.BigInteger;
import java.util.List;
import java.util.Random;
public class Mixer implements meerkat.crypto.mixnet.Mixer {
protected final Random random;
protected final Mix2ZeroKnowledgeProver prover;
protected final Encryption encryptor;
protected final Mix2ZeroKnowledgeVerifier verifier;
public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc) {
this.random = rand;
this.prover = prov;
this.encryptor = enc;
this.verifier = null;
}
public Mixer(Random rand, Mix2ZeroKnowledgeProver prov, Encryption enc,Mix2ZeroKnowledgeVerifier verifier) {
this.random = rand;
this.prover = prov;
this.encryptor = enc;
this.verifier = verifier;
}
// assert n = 2^k and n > 1
protected boolean inputBasicCheckSum(int n){
return n > 1 && ((n & (n - 1)) == 0);
}
protected RerandomizableEncryptedMessage[][] initializeEncryptionTable(int n,int layers,List<RerandomizableEncryptedMessage> 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;
}
protected EncryptionRandomness[][] generateRandomnessesForRerandomize(int n,int layers){
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;
}
protected MixNetwork createMixNetwork(int n){
return new MixNetwork(new RandomPermutation(n,random));
}
protected 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);
}
}
}
}
protected ZeroKnowledgeProof[][] createZKPTable(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;
}
public MixerOutput mix(List<RerandomizableEncryptedMessage> ciphertexts) throws InvalidProtocolBufferException {
int n = ciphertexts.size();
if (!inputBasicCheckSum(n))
return null;
int layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1
RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts);
EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers);
MixNetwork mixNetwork = createMixNetwork(n);
BigInteger time = BigInteger.valueOf(System.currentTimeMillis());
rerandomize(layers,mixNetwork,encryptionTable,randomnesses);
System.out.println("re enc time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time));
time = BigInteger.valueOf(System.currentTimeMillis());
ZeroKnowledgeProof[][] proofsTable = createZKPTable(n,layers,mixNetwork,encryptionTable,randomnesses);
System.out.println("zkp time : " + BigInteger.valueOf(System.currentTimeMillis()).subtract(time));
return new mixer.MixerOutput(n,layers,proofsTable, encryptionTable);
}
}

View File

@ -1,106 +0,0 @@
package mixer;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by Tzlil on 1/18/2016.
*/
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;
public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
this.proofs = proofs;
this.encryptedMessages = encryptedMessages;
this.n = n;
this.layers = layers;
}
public MixerOutput(meerkat.crypto.mixnet.MixerOutput mixerOutput) {
this.proofs = mixerOutput.getProofs();
this.encryptedMessages = mixerOutput.getEncryptedMessages();
this.n = mixerOutput.getN();
this.layers = (int) (2 * Math.log(n) / Math.log(2)) - 1; // layers = 2logn -1;
}
@Override
public Mixing.ZeroKnowledgeProof[][] getProofs() {
return proofs;
}
@Override
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() {
return encryptedMessages;
}
@Override
public int getN() {
return n;
}
public void outToFile(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]);
}
}
}
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();
}
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();
}
}

View File

@ -1,32 +0,0 @@
package mixer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by Tzlil on 12/17/2015.
*/
class RandomPermutation {
protected final int[] permutation;
protected RandomPermutation(int n,Random random)
{
List<Integer> numbers= new ArrayList<Integer>(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);
}
permutation = result;
}
}

View File

@ -1,28 +0,0 @@
package mixer;
/**
* Created by Tzlil on 12/15/2015.
*/
public class Switch{
public final int i, j, layer;
public final boolean value;
public Switch(int i, int j, int layer, boolean value) {
this.i = i;
this.j = j;
this.layer = layer;
this.value = value;
}
@Override
public String toString() {
return "Switch{" +
"i=" + i +
", j=" + j +
", layer=" + layer +
", value=" + value +
'}';
}
}

View File

@ -1,78 +0,0 @@
package necessary;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 14-Dec-15.
*/
public interface AsyncBulletinBoardClient extends BulletinBoardClient {
public interface ClientCallback<T> {
void handleCallback(T msg);
void handleFailure(Throwable t);
}
public interface MessageHandler {
void handleNewMessages(List<BulletinBoardMessage> 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<BatchData> 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<BatchData> 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<Float> 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<List<BulletinBoardMessage>> 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<CompleteBatch> 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);
}

View File

@ -1,63 +0,0 @@
package necessary;
/**
* Created by Tzlil on 12/27/2015.
*/
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.*;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.util.List;
/**
* Created by talm on 24/10/15.
*/
public interface BulletinBoardClient {
interface ClientCallback<T> {
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<BulletinBoardMessage> readMessages(MessageFilterList filterList);
/**
* Closes all connections, if any.
* This is msgRecived in a synchronous (blocking) way.
*/
void close();
}

View File

@ -1,68 +0,0 @@
package necessary;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.*;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 14-Dec-15.
*
* A data structure for holding a complete batch message along with its signature
*/
public class CompleteBatch {
private BeginBatchMessage beginBatchMessage;
private List<BatchData> batchDataList;
private Signature signature;
public CompleteBatch() {
batchDataList = new LinkedList<BatchData>();
}
public CompleteBatch(BeginBatchMessage newBeginBatchMessage) {
this();
beginBatchMessage = newBeginBatchMessage;
}
public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List<BatchData> newDataList) {
this(newBeginBatchMessage);
appendBatchData(newDataList);
}
public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List<BatchData> newDataList, Signature newSignature) {
this(newBeginBatchMessage, newDataList);
signature = newSignature;
}
public BeginBatchMessage getBeginBatchMessage() {
return beginBatchMessage;
}
public List<BatchData> 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<BatchData> newBatchDataList) {
batchDataList.addAll(newBatchDataList);
}
public void setSignature(Signature newSignature) {
signature = newSignature;
}
}

View File

@ -1,303 +0,0 @@
package 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;
/**
* use for organize the input for each ZKP
*
* both prover and 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 prover only
*
* call to the 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 verifier
*
* call to the 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 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 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 prover
* call to the 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 prover
* call to the 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 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 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 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;
}
/**
* use by verifier
*/
private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) {
this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown);
}
}
}

View File

@ -1,215 +0,0 @@
package 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;
/**
* implements of Mix2ZeroKnowledgeProver interface
* this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext
*/
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 FiatShamir 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;
}
/**
* FiatShamir heuristic
* @param input - protobuf contains all parameters from the first step of the current prove
* @return randomOracle.hash(input)
*/
private BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) {
byte[] arr = input.toByteArray();
return new BigInteger(1,this.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 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).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).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();
}
}

View File

@ -1,121 +0,0 @@
package 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 prover.ElGamalProofOrganizer;
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
public class Verifier implements Mix2ZeroKnowledgeVerifier {
private final ECGroup group;
private final RandomOracle randomOracle;
private final ECElGamalEncryption encryptor;
private final ECPoint g,h;
private final ElGamalProofOrganizer organizer;
private final ZeroKnowledgeOrProofParser parser;
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.organizer = new ElGamalProofOrganizer(group,g,h);
this.parser = new ZeroKnowledgeOrProofParser(group);
}
public BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) {
byte[] arr = input.toByteArray();
return new BigInteger(1,this.randomOracle.hash(arr,arr.length));
}
/**
* @return true iff the proof is valid
*/
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());
}
public boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput,
Mixing.ZeroKnowledgeProof.OrProof orProof) {
ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof);
List<Condition> conditions = createConditionsList(orProofInput,container);
boolean result = true;
for (Condition condition: conditions) { //temporary
if(!condition.test()){
if (result){
result = false;
System.out.print("\n\n\n");
}
System.out.println(condition.errorDescription);
}
}
return result;
}
private List<Condition> createConditionsList(ElGamalProofOrganizer.OrProofInput orProofInput
,ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container){
List<Condition> conditions = new ArrayList<Condition>();
conditions.add(new Condition<ECPoint>( container.g1,orProofInput.g1,"g1 != g"));
conditions.add(new Condition<ECPoint>( container.h1,orProofInput.h1,"h1 != e1New.c1/e1.c1"));
conditions.add(new Condition<ECPoint>( container.g2,orProofInput.g2,"g2 != h"));
conditions.add(new Condition<ECPoint>( container.h2,orProofInput.h2,"h2 != e1New.c2/e1.c2"));
conditions.add(new Condition<ECPoint>( container.g1Tag,orProofInput.g1Tag,"g1Tag != g"));
conditions.add(new Condition<ECPoint>( container.h1Tag,orProofInput.h1Tag,"h1Tag != e2New.c1/e2.c1"));
conditions.add(new Condition<ECPoint>( container.g2Tag,orProofInput.g2Tag,"g2Tag != h"));
conditions.add(new Condition<ECPoint>( container.h2Tag,orProofInput.h2Tag,"h2Tag != e2New.c2/e2.c2"));
conditions.add(new Condition<BigInteger>(container.c1.add(container.c2).mod(group.orderUpperBound()),
hash(container.forRandomOracle).mod(group.orderUpperBound()).mod(group.orderUpperBound()),
"(c1 + c2 ) % group size == hash (imput + step1) % group size"));
conditions.add(new Condition<ECPoint>( group.multiply(container.g1, container.z),
group.add(container.u, group.multiply(container.h1,container.c1)),"g1 ^ z != u * ( h1 ^ c1 )"));
conditions.add(new Condition<ECPoint>( group.multiply(container.g2, container.z),
group.add(container.v, group.multiply(container.h2,container.c1)),"g2 ^ z != v * ( h2 ^ c1 )"));
conditions.add(new Condition<ECPoint>( group.multiply(container.g1Tag, container.zTag),
group.add(container.uTag, group.multiply(container.h1Tag,container.c2))
,"g1Tag ^ zTag != uTag * ( h1Tag ^ c2 )"));
conditions.add(new Condition<ECPoint>( group.multiply(container.g2Tag, container.zTag),
group.add(container.vTag, group.multiply(container.h2Tag,container.c2))
,"g2Tag ^ zTag != vTag * ( h2Tag ^ c2 )"));
return conditions;
}
private class Condition<T>{
T given, expected;
String errorDescription;
Condition(T given,T expected,String description){
this.given = given;
this.errorDescription = description;
this.expected = expected;
}
boolean test(){
return given.equals(expected);
}
}
}

View File

@ -1,88 +0,0 @@
package 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 12/30/2015.
*/
public final class VerifyTable {
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];
if(zkp == null){
int ttt = 1;
ttt++;
}
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);
System.out.print("\n\n\nlayer " + layer + " i , j " + index1 + " , " + index2 + "\n\n\n");
return false;
}
}
}
// verify all necessary locations for BeneshNet were proved
for (boolean[] checksumLayer: locationChecksum) {
for (boolean locationBoolean: checksumLayer) {
if (!locationBoolean)
return false;
}
}
return true;
}
}

View File

@ -1,69 +0,0 @@
package 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 1/25/2016.
*/
public class ZeroKnowledgeOrProofParser {
private final ECGroup group;
public ZeroKnowledgeOrProofParser(ECGroup group) {
this.group = group;
}
public ECPoint convert2ECPoint(ByteString bs){
return group.decode(bs.toByteArray());
}
public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){
return new ZeroKnowledgeOrProofContainer(orProof);
}
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;
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());
}
}
}

View File

@ -1,10 +1,13 @@
package mixer;
package meerkat.mixer;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
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;

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
/**
* Created by Tzlil on 12/17/2015.

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
/**
* Created by Tzlil on 12/30/2015.

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
import com.google.protobuf.ByteString;
import com.google.protobuf.GeneratedMessage;

View File

@ -1,4 +1,4 @@
package mixer;
package meerkat.mixer;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;