Refactoring (tests currently fail)

mixer
Tal Moran 2017-01-19 11:08:07 +02:00
parent 78f823f31e
commit fc2c26d7e9
34 changed files with 584 additions and 1035 deletions

View File

@ -1,20 +0,0 @@
package meerkat.crypto.mixnet;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
/**
* Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts.
*/
public interface Mix2ZeroKnowledgeProver {
public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage in1,
Crypto.RerandomizableEncryptedMessage in2,
Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2,
boolean switched,int i,int j, int layer, // switch info
Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException;
}

View File

@ -0,0 +1,20 @@
package meerkat.crypto.mixnet;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
/**
* Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts.
*/
public interface Mix2ZeroKnowledgeProver {
public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage in1,
Crypto.RerandomizableEncryptedMessage in2,
Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2,
boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx, // switch info
Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException;
}

View File

@ -9,5 +9,6 @@ import meerkat.protobuf.Mixing;
public interface MixerOutput {
public Mixing.Mix2Proof[][] getProofs();
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages();
public int getN();
public int getLogN();
public int getNumLayers();
}

View File

@ -15,37 +15,6 @@ import java.util.List;
* provide convert operation from batch data to meerkat.mixer.mixing output and backwards
*/
public class BatchConverter {
private final int n,layers;
/**
* constructor
* @param n
* @param layers
*/
public BatchConverter(int n,int layers){
this.n = n;
this.layers = layers;
}
/**
* convert integer to byte string
* @param a
* @return a as byte string
*/
private ByteString Integer2ByteString(int a){
return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray());
}
/**
* convert byte string to integer
* @param bs
* @return bs as int
*/
private int ByteString2Integer(ByteString bs) {
return Integer.valueOf(bs.toString());
}
/**
* convert meerkat.mixer.mixing output to batch data
* @param mixerOutput
@ -55,8 +24,13 @@ public class BatchConverter {
List<BulletinBoardAPI.BatchChunk> result = new ArrayList<BulletinBoardAPI.BatchChunk>();
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.newBuilder()
.setLogN(mixerOutput.getLogN())
.setLayers(mixerOutput.getNumLayers())
.build();
result.add(BulletinBoardAPI.BatchChunk.newBuilder()
.setData(Integer2ByteString(n))
.setData(header.toByteString())
.build());
for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) {
@ -85,10 +59,11 @@ public class BatchConverter {
public MixerOutput BatchChunkList2MixerOutput
(List<BulletinBoardAPI.BatchChunk> batchChunkList) throws Exception {
if (n != ByteString2Integer(batchChunkList.remove(0).getData())){
throw new Exception();
}
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseFrom(batchChunkList.remove(0).getData());
int logN = header.getLogN();
int n = 1 << logN;
int layers = header.getLayers();
int nDiv2 = n >>1;
Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2];
for (int layer = 0; layer < layers; layer++)
@ -110,7 +85,7 @@ public class BatchConverter {
}
}
return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions);
return new meerkat.mixer.mixing.MixerOutput(logN, proofs,encryptions);
}

View File

@ -21,19 +21,14 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
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) {
public BatchHandler(Mix2ZeroKnowledgeVerifier verifier) {
this.mixerOutput = null;
this.n = n;
this.layers = layers;
this.msgReceived = false;
this.t = null;
this.verifier = verifier;
@ -70,7 +65,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
* @throws Exception
*/
private void convertMessage() throws Exception {
BatchConverter batchConverter = new BatchConverter(n,layers);
BatchConverter batchConverter = new BatchConverter();
this.mixerOutput = batchConverter.BatchChunkList2MixerOutput(msg.getBatchChunkList());
}
@ -83,7 +78,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
if (mixerOutput == null) {
convertMessage();
}
return VerifyTable.verifyTable(verifier, n, mixerOutput);
return VerifyTable.verifyTable(verifier, mixerOutput);
}
/**
@ -98,7 +93,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
if(!verifyTable()){
throw new Exception("in valid table");
}
return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1
return Arrays.asList(mixerOutput.getEncryptedMessages()[mixerOutput.getNumLayers()]);//there are layers + 1
}
}

View File

@ -5,7 +5,6 @@ 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;
@ -26,7 +25,6 @@ public class MainMixing {
private final Mixer mixer;
private final Mix2ZeroKnowledgeVerifier verifier;
private final int n, layers;
private final AsyncBulletinBoardClient asyncBulletinBoardClient;
private final byte[] id;
@ -35,16 +33,13 @@ public class MainMixing {
* constructor
* @param mixer
* @param verifier
* @param n
* @param asyncBulletinBoardClient
* @param id
*/
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n
, AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier,
AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
this.mixer = mixer;
this.verifier = verifier;
this.n = n;
this.layers = MixNetwork.numberOfLayers(n);
this.asyncBulletinBoardClient = asyncBulletinBoardClient;
this.id = id;
}
@ -64,7 +59,7 @@ public class MainMixing {
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
BatchHandler currentBatchHandler;
for (Integer prevBatchId : prevBatchIds) {
currentBatchHandler = new BatchHandler(n, layers,verifier);
currentBatchHandler = new BatchHandler(verifier);
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
batchHandlers.add(currentBatchHandler);
}
@ -99,7 +94,7 @@ public class MainMixing {
private void updateBB(MixerOutput mixerOutput
, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) {
BatchConverter batchConverter = new BatchConverter(n,layers);
BatchConverter batchConverter = new BatchConverter();
List<BulletinBoardAPI.BatchChunk> batchChunkList = batchConverter.MixerOutput2BatchChunk(mixerOutput);
asyncBulletinBoardClient.postBatch(id, batchId, batchChunkList, callback);
}

View File

@ -1,214 +0,0 @@
package meerkat.mixer.mixing;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
/**
* Created by Tzlil on 12/15/2015.
* contains benes mix network.
* the network is generated in the constructor and can't be change
*/
public class MixNetwork {
private final Switch[][] switches;
/**
* constructor
* @param randomPermutation
*/
public MixNetwork(RandomPermutation randomPermutation) {
this.switches = generateSwitchesValue(randomPermutation.permutation);
}
/**
* implements Benes mix network algorithm
* @param permutation - random permutation
* @return switches
*/
private Switch[][] generateSwitchesValue(int[] permutation){
int n = permutation.length;
assert ((n & n-1) == 0); //n == 2^k
int layers = numberOfLayers(n);
int[] pi, piL, piR;
Queue<int[]> permutationsQueue = new ArrayBlockingQueue<int[]>(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<Edge> edges;
private boolean value;
private boolean set;
public Node() {
edges = new ArrayList<Edge>(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;
}
}
}
}

View File

@ -80,89 +80,96 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
/**
* generate new random mix network
* @param n number of votes
* @param logN log number of votes
* @param random
* @return new random mix network
*/
private MixNetwork generateMixNetwork(int n,Random random){
return new MixNetwork(new RandomPermutation(n,random));
private PermutationNetwork generateMixNetwork(int logN, Random random){
BenesNetwork net = new BenesNetwork(logN);
RandomPermutation perm = new RandomPermutation(1 << logN, random);
net.setPermutation(perm.permutation);
return net;
}
/**
* fills the encryption table with rerandomize encrypted votes.
* @param layers
* fills the encryption table with rerandomized encrypted votes.
* @param mixNetwork switches table (boolean values)
* @param encryptionTable an initialized encryption table s.t first layer == given encrypted votes
* @param randomnesses an initialized randomness table of size layers * n, use for rerandomize operations
* @throws InvalidProtocolBufferException
*/
private void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
private void rerandomize(PermutationNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
Switch[] switchesLayer;
int index1,index2;
RerandomizableEncryptedMessage e1,e2;
RerandomizableEncryptedMessage a,b;
EncryptionRandomness r1,r2;
for (int layer = 0; layer < layers; layer++)
{
switchesLayer = mixNetwork.getSwitchesByLayer(layer);
for (Switch sw : switchesLayer) {
index1 = sw.i;
index2 = sw.j;
e1 = encryptionTable[layer][index1];
e2 = encryptionTable[layer][index2];
int layers = mixNetwork.getNumLayers();
r1 = randomnesses[layer][index1];
r2 = randomnesses[layer][index2];
if (!sw.value) {
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1);
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2);
int numSwitches = mixNetwork.getNumInputs() >>> 1;
for (int layer = 0; layer < layers; layer++) {
for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) {
boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx);
int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx);
int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
r1 = randomnesses[layer][2 * switchIdx];
r2 = randomnesses[layer][2 * switchIdx + 1];
a = encryptionTable[layer][2 * switchIdx];
b = encryptionTable[layer][2 * switchIdx + 1];
if (isCrossed) {
encryptionTable[layer + 1][out0] = encryptor.rerandomize(b, r2);
encryptionTable[layer + 1][out1] = encryptor.rerandomize(a, r1);
} else {
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2);
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1);
encryptionTable[layer + 1][out0] = encryptor.rerandomize(a, r1);
encryptionTable[layer + 1][out1] = encryptor.rerandomize(b, r2);
}
}
}
}
/**
* generate zero knowledge proof for each rerandomize encrypted votes couple in encryptionTable
* @param n number of votes
* @param layers
* @param mixNetwork switches table (boolean values) used for set encryption table
* @param encryptionTable full encryption table
* @param randomnesses randomness table of size layers * n, used for set encryption table
* @return zero knowledge proofs table
* @throws InvalidProtocolBufferException
*/
private Mix2Proof[][] generateMix2ProofTable(int n, int layers, MixNetwork mixNetwork
private Mix2Proof[][] generateMix2ProofTable(PermutationNetwork mixNetwork
, RerandomizableEncryptedMessage[][] encryptionTable
, EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
int layers = mixNetwork.getNumLayers();
int n = mixNetwork.getNumInputs();
Switch[] switchesLayer;
int index1,index2;
int switchIndex = 0;
int nDiv2 = n >> 1;
Mix2Proof[][] proofsTable = new Mix2Proof[layers][nDiv2];
int numSwitches = n >> 1;
Mix2Proof[][] proofsTable = new Mix2Proof[layers][numSwitches];
RerandomizableEncryptedMessage e1,e2;
RerandomizableEncryptedMessage a,b,c,d;
EncryptionRandomness r1,r2;
for (int layer = 0; layer < layers; layer++)
{
switchesLayer = mixNetwork.getSwitchesByLayer(layer);
for (Switch sw : switchesLayer) {
index1 = sw.i;
index2 = sw.j;
e1 = encryptionTable[layer][index1];
e2 = encryptionTable[layer][index2];
r1 = randomnesses[layer][index1];
r2 = randomnesses[layer][index2];
for (int layer = 0; layer < layers; layer++) {
for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) {
boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx);
int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx);
int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
a = encryptionTable[layer][2 * switchIdx];
b = encryptionTable[layer][2 * switchIdx + 1];
c = encryptionTable[layer + 1][out0];
d = encryptionTable[layer + 1][out1];
r1 = randomnesses[layer][2 * switchIdx];
r2 = randomnesses[layer][2 * switchIdx + 1];
proofsTable[layer][switchIndex] =
prover.prove(e1, e2, encryptionTable[layer + 1][index1],
encryptionTable[layer + 1][index2],
sw.value, sw.i, sw.j, sw.layer, r1, r2);
switchIndex = (switchIndex + 1) % nDiv2;
prover.prove(a, b, c, d, isCrossed, layer, switchIdx, out0, out1, r1, r2);
}
}
return proofsTable;
@ -180,14 +187,18 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
int n = ciphertexts.size();
assert (n > 1 && isPowerOfTwo(n));
int layers = MixNetwork.numberOfLayers(n); // layers = 2logn -1
int logN = Integer.numberOfTrailingZeros(Integer.highestOneBit(n)) + 1;
PermutationNetwork net = generateMixNetwork(logN,random);
int layers = net.getNumLayers();
RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts);
EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random);
MixNetwork mixNetwork = generateMixNetwork(n,random);
rerandomize(layers,mixNetwork,encryptionTable,randomnesses);
Mix2Proof[][] proofsTable = generateMix2ProofTable(n,layers,mixNetwork,encryptionTable,randomnesses);
return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable);
rerandomize(net,encryptionTable,randomnesses);
Mix2Proof[][] proofsTable = generateMix2ProofTable(net,encryptionTable,randomnesses);
return new meerkat.mixer.mixing.MixerOutput(logN, proofsTable, encryptionTable);
}
}

View File

@ -13,26 +13,23 @@ import java.io.IOException;
* implements meerkat.crypto.mixnet.MixerOutput interface
* container for meerkat.mixer.mixing.mix result.
*/
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput {
private final Mixing.Mix2Proof[][] proofs;
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
private final int n;
private final int layers;
private final int logN;
/**
* constructor
* @param n number of votes
* @param layers
* @param logN log (base 2) of the number of votes
* @param encryptedMessages at level 0 , contains the original encrypted votes
* at each other level contains the re encrypted votes
* @param proofs in each cell (level,switch) contains the match zero knowledge proof
*/
public MixerOutput(int n,int layers,Mixing.Mix2Proof[][] proofs
public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs
, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
this.proofs = proofs;
this.encryptedMessages = encryptedMessages;
this.n = n;
this.layers = layers;
this.logN = logN;
}
@ -48,8 +45,13 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
}
@Override
public int getN() {
return n;
public int getLogN() {
return logN;
}
@Override
public int getNumLayers() {
return 2 * logN - 1;
}
/**
@ -57,33 +59,33 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
* @param dir - directory
* @throws IOException
*/
public void outToFolder(String dir) throws IOException {
(new File(dir)).mkdirs();
//create files
String proofsDir = dir + "/Proofs";
String encDir = dir + "/EncryptedMessages";
(new File(proofsDir)).mkdir();
(new File(encDir)).mkdir();
for (int layer = 0; layer < layers; layer++){
(new File(proofsDir +"/layer" + layer )).mkdir();
(new File(encDir +"/layer" + layer )).mkdir();
}
(new File(encDir +"/input")).mkdir();
for (int layer = 0; layer < layers; layer++){
for(int i = 0; i < proofs[layer].length; i ++){
writeProofToFile(proofsDir,proofs[layer][i]);
}
}
for (int layer = 0; layer <= layers; layer++){
for(int i = 0; i < encryptedMessages[layer].length; i ++){
writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
}
}
}
// public void outToFolder(String dir) throws IOException {
//
// (new File(dir)).mkdirs();
// //create files
// String proofsDir = dir + "/Proofs";
// String encDir = dir + "/EncryptedMessages";
// (new File(proofsDir)).mkdir();
// (new File(encDir)).mkdir();
// for (int layer = 0; layer < layers; layer++){
// (new File(proofsDir +"/layer" + layer )).mkdir();
// (new File(encDir +"/layer" + layer )).mkdir();
// }
// (new File(encDir +"/input")).mkdir();
//
//
// for (int layer = 0; layer < layers; layer++){
// for(int i = 0; i < proofs[layer].length; i ++){
// writeProofToFile(proofsDir,proofs[layer][i]);
// }
// }
//
// for (int layer = 0; layer <= layers; layer++){
// for(int i = 0; i < encryptedMessages[layer].length; i ++){
// writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
// }
// }
// }
/**
* create new file contains single proof
@ -91,19 +93,19 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
* @param proof
* @throws IOException
*/
private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
Mixing.Mix2Proof.Location location = proof.getLocation();
int layer = location.getLayer();
int i = location.getI();
int j = location.getJ();
String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
File file = new File(fileName);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos.write(proof.toByteArray());
fos.close();
}
// private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
// Mixing.Mix2Proof.Location location = proof.getLocation();
// int layer = location.getLayer();
// int i = location.getI();
// int j = location.getJ();
// String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
//
// File file = new File(fileName);
// file.createNewFile();
// FileOutputStream fos = new FileOutputStream(file);
// fos.write(proof.toByteArray());
// fos.close();
// }
/**
* create new file contains single encrypted message

View File

@ -0,0 +1,39 @@
package meerkat.mixer.proofs;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.protobuf.Mixing;
import java.util.Random;
/**
* Sigma protocol for plaintext equivalence of a pair of ciphertexts.
*/
public class DlogConjunction {
public static class Prover
extends SigmaProtocolAnd2.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
public Prover(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.AndStatement statement,
ECElGamalMixStatementGenerator.AndStatementWitness witness) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, new SchnorrDlogEquivalence.Prover(encryptor, rand, statement.clauses[0], witness.witnesses[0]),
new SchnorrDlogEquivalence.Prover(encryptor, rand, statement.clauses[1], witness.witnesses[1]));
}
}
public static class Simulator extends SigmaProtocolAnd2.Simulator {
public Simulator(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.AndStatement statement) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement.clauses[0]), new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement.clauses[1]));
}
}
public static class Verifier
extends SigmaProtocolAnd2.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.AndStatement statement) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[0]), new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[1]));
}
}
}

View File

@ -1,184 +0,0 @@
package meerkat.mixer.proofs;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.protobuf.ConcreteCrypto.GroupElement;
import meerkat.protobuf.Mixing;
import meerkat.protobuf.Mixing.Mix2Proof.AndProof;
import meerkat.protobuf.Mixing.Mix2Proof.DlogProof;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import java.math.BigInteger;
import java.util.Random;
import static meerkat.protobuf.Mixing.Mix2Proof.DlogProof.*;
/**
* Prover, Simulator and Verifier
*/
public class ECElGamalMixProtocols {
final ECElGamalMixParams params;
final ECGroup group;
final ECElGamalEncryption encryptor;
final ECPoint g;
final ECPoint h;
final Random rand;
final ChallengeGenerator challengeGenerator = new ChallengeGenerator();
public ECElGamalMixProtocols(ECElGamalMixParams params, Random rand) {
this.params = params;
this.rand = rand;
group = params.group;
encryptor = params.encryptor;
g = params.g;
h = params.h;
}
public class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator {
@Override
public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); }
@Override
public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); }
}
public class DlogStatementSchnorrProver implements SigmaProtocol.Prover<DlogProof.FirstMessage, DlogProof.FinalMessage> {
ECElGamalMixParams.DlogStatement statement;
ECElGamalMixParams.DlogStatementWitness witness;
BigInteger r = null;
public DlogStatementSchnorrProver(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) {
this.statement = statement;
this.witness = witness;
}
@Override
public FirstMessage getFirstMessage() {
r = encryptor.generateRandomExponent(rand);
ECPoint gr = group.multiply(statement.g, r);
ECPoint hr = group.multiply(statement.h, r);
FirstMessage firstMessage = FirstMessage.newBuilder()
.setGr(encryptor.encodeElement(gr))
.setHr(encryptor.encodeElement(hr))
.build();
return firstMessage;
}
@Override
public FinalMessage getFinalMessage(BigInteger challenge) {
return FinalMessage.newBuilder()
.setXcr(Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound())))
.build();
}
@Override
public void reset() { r = null; }
}
public class DlogStatementSchnorrVerifier implements SigmaProtocol.Verifier<DlogProof.FirstMessage, DlogProof.FinalMessage> {
final ECElGamalMixParams.DlogStatement statement;
public DlogStatementSchnorrVerifier(ECElGamalMixParams.DlogStatement statement) {
this.statement = statement;
}
@Override
public boolean verify(FirstMessage firstMessage, BigInteger challenge,
FinalMessage finalMessage) {
GroupElement grEncoded = firstMessage.getGr();
ECPoint gr = encryptor.decodeElement(grEncoded);
GroupElement hrEncoded = firstMessage.getHr();
ECPoint hr = encryptor.decodeElement(hrEncoded);
BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr());
boolean gGood = group.add(gr, group.multiply(statement.a,challenge)).equals(group.multiply(statement.g,xcr));
boolean hGood = group.add(hr, group.multiply(statement.b,challenge)).equals(group.multiply(statement.h,xcr));
return gGood && hGood;
}
}
public class DlogStatementSchnorrSimulator implements SigmaProtocol.Simulator<DlogProof.FirstMessage, DlogProof.FinalMessage> {
ECElGamalMixParams.DlogStatement statement;
BigInteger response = null;
public DlogStatementSchnorrSimulator(ECElGamalMixParams.DlogStatement statement) {
this.statement = statement;
}
@Override
public FirstMessage getFirstMessage(BigInteger challenge) {
response = encryptor.generateRandomExponent(rand);
ECPoint u = group.multiply(statement.g, response).subtract(group.multiply(statement.a,challenge));
ECPoint v = group.multiply(statement.h, response).subtract(group.multiply(statement.b,challenge));
return FirstMessage.newBuilder()
.setGr(encryptor.encodeElement(u))
.setHr(encryptor.encodeElement(v))
.build();
}
@Override
public FinalMessage getFinalMessage() {
return FinalMessage.newBuilder()
.setXcr(Util.encodeBigInteger(response))
.build();
}
@Override
public void reset() { response = null; }
}
/**
* Prover for plaintext equivalence of a pair of ciphertexts.
*/
public class AndStatementProver
extends SigmaProtocolAnd2.Prover<AndProof.FirstMessage, DlogProof.FirstMessage, AndProof.FinalMessage, DlogProof.FinalMessage> {
public AndStatementProver(ECElGamalMixParams.AndStatement statement,
ECElGamalMixParams.AndStatementWitness witness) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, new DlogStatementSchnorrProver(statement.clauses[0], witness.witnesses[0]),
new DlogStatementSchnorrProver(statement.clauses[1], witness.witnesses[1]));
}
}
public class AndStatementVerifier
extends SigmaProtocolAnd2.Verifier<AndProof.FirstMessage, DlogProof.FirstMessage, AndProof.FinalMessage, DlogProof.FinalMessage> {
public AndStatementVerifier(ECElGamalMixParams.AndStatement statement) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
new DlogStatementSchnorrVerifier(statement.clauses[0]), new DlogStatementSchnorrVerifier(statement.clauses[1]));
}
}
public class AndStatementSimulator extends SigmaProtocolAnd2.Simulator {
public AndStatementSimulator(ECElGamalMixParams.AndStatement statement) {
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
new DlogStatementSchnorrSimulator(statement.clauses[0]), new DlogStatementSchnorrSimulator(statement.clauses[1]));
}
}
public class Mix2Prover extends SigmaProtocolOr2.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
public Mix2Prover(ECElGamalMixParams.Mix2Statement statement, ECElGamalMixParams.Mix2StatementWitness witness) {
super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator,
new AndStatementProver(statement.clauses[witness.trueClauseIndex], witness.witness),
new AndStatementSimulator(statement.clauses[1 - witness.trueClauseIndex]),
witness.trueClauseIndex);
}
}
public class Mix2Verifier extends SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
public Mix2Verifier(ECElGamalMixParams.Mix2Statement statement) {
super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator,
new AndStatementVerifier(statement.clauses[0]), new AndStatementVerifier(statement.clauses[1]));
}
}
}

View File

@ -16,7 +16,7 @@ import java.math.BigInteger;
*
* both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it
*/
public class ECElGamalMixParams {
public class ECElGamalMixStatementGenerator {
final ECElGamalEncryption encryptor;
final ECGroup group;
@ -31,7 +31,7 @@ public class ECElGamalMixParams {
* @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
* second base (h) are taken from the encryptor (second base is the public key)
*/
public ECElGamalMixParams(ECElGamalEncryption encryptor){
public ECElGamalMixStatementGenerator(ECElGamalEncryption encryptor){
this.encryptor = encryptor;
this.group = encryptor.getGroup();
this.g = group.getGenerator();
@ -40,11 +40,6 @@ public class ECElGamalMixParams {
this.hEncoded = encryptor.encodeElement(h);
}
public enum TrueCouple {
left, right, unknown
}
/**
* can be used by anyone, e.g meerkat.mixer.verifier
*
@ -84,7 +79,7 @@ public class ECElGamalMixParams {
*
* The actual stored data is a cached representation for use in proofs and verification. This consists of the four substatements that are ORs of the DLOG equality.
*
* A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixParams (all constructors are private)
* A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixStatementGenerator (all constructors are private)
*
*/
public class Mix2Statement {
@ -180,9 +175,9 @@ public class ECElGamalMixParams {
DlogStatement(ECPoint a, ECPoint b) {
this.g = ECElGamalMixParams.this.g;
this.g = ECElGamalMixStatementGenerator.this.g;
this.a = a;
this.h = ECElGamalMixParams.this.h;
this.h = ECElGamalMixStatementGenerator.this.h;
this.b = b;
}
}

View File

@ -0,0 +1,46 @@
package meerkat.mixer.proofs;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.protobuf.Mixing;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import java.math.BigInteger;
import java.util.Random;
/**
* Sigma protocol for proving correctness of a 2x2 switch
*/
public class Mix2 {
public static class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator {
ECElGamalEncryption encryptor;
ECGroup group;
Random rand;
public ChallengeGenerator(ECElGamalEncryption encryptor, Random rand) {
this.encryptor = encryptor;
group = encryptor.getGroup();
}
@Override
public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); }
@Override
public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); }
}
public static class Prover extends SigmaProtocolOr2.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
public Prover(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.Mix2Statement statement, ECElGamalMixStatementGenerator.Mix2StatementWitness witness) {
super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, rand),
new DlogConjunction.Prover(encryptor, rand, statement.clauses[witness.trueClauseIndex], witness.witness),
new DlogConjunction.Simulator(encryptor, rand, statement.clauses[1 - witness.trueClauseIndex]),
witness.trueClauseIndex);
}
}
public static class Verifier extends SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.Mix2Statement statement) {
super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, null),
new DlogConjunction.Verifier(encryptor, statement.clauses[0]), new DlogConjunction.Verifier(encryptor, statement.clauses[1]));
}
}
}

View File

@ -2,7 +2,6 @@ package meerkat.mixer.proofs;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
@ -26,8 +25,7 @@ public class Prover implements Mix2ZeroKnowledgeProver {
private final ECElGamalEncryption encryptor;
private final ECPoint g,h;
private final BigInteger groupOrderUpperBound;
private final ECElGamalMixParams mixParams;
final ECElGamalMixProtocols mixProtocols;
private final ECElGamalMixStatementGenerator mixParams;
final SigmaFiatShamir<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> mix2NIZK;
/**
@ -43,9 +41,8 @@ public class Prover implements Mix2ZeroKnowledgeProver {
this.group = this.encryptor.getGroup();
this.g = group.getGenerator();
this.h = this.encryptor.getElGamalPK().getPK();
this.mixParams = new ECElGamalMixParams(encryptor);
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
this.groupOrderUpperBound = group.orderUpperBound();
this.mixProtocols = new ECElGamalMixProtocols(mixParams, rand); // We don't need randomness for the verifier
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
}
@ -55,8 +52,6 @@ public class Prover implements Mix2ZeroKnowledgeProver {
* @param c - if switched then c = rerandomize(b,r2) else c = rerandomize(a,r1)
* @param d - if switched then d = rerandomize(a,r1) else d = rerandomize(b,r2)
* @param switched - trueClauseIndex
* @param i - column of a and c in encryption table
* @param j - column of b and d in encryption table
* @param layer - row of a,b in encryption table
* @param r1
* @param r2
@ -67,186 +62,25 @@ public class Prover implements Mix2ZeroKnowledgeProver {
Crypto.RerandomizableEncryptedMessage b,
Crypto.RerandomizableEncryptedMessage c,
Crypto.RerandomizableEncryptedMessage d,
boolean switched,int i,int j, int layer,
boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx,
Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(a,b,c,d);
ECElGamalMixParams.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(a, b, c, d);
ECElGamalMixStatementGenerator.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
ECElGamalMixProtocols.Mix2Prover prover = mixProtocols.new Mix2Prover(statement, witness);
Mix2.Prover prover = new Mix2.Prover(encryptor, rand, statement, witness);
Mixing.Mix2Proof.Location location = Mixing.Mix2Proof.Location.newBuilder()
.setI(i)
.setJ(j)
.setLayer(layer).build();
.setLayer(layer)
.setSwitchIdx(switchIdx)
.setOut0(out0Idx)
.setOut1(out1Idx)
.build();
return mix2NIZK.generateNizk(prover).toBuilder().setLocation(location).build();
// Mixing.Mix2Proof first,second,third,fourth;
//
// ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched);
//
// first = createOrProof(statement.getDlogStatement(0));
// second = createOrProof(statement.getDlogStatement(1));
// third = createOrProof(statement.getDlogStatement(2));
// fourth = createOrProof(statement.getDlogStatement(3));
//
// Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
// .setI(i)
// .setJ(j)
// .setLayer(layer)
// .build();
//
// Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder()
// .setFirst(first)
// .setSecond(second)
// .setThird(third)
// .setFourth(fourth)
// .setLocation(location)
// .build();
// return result;
}
//
//
// Mixing.Mix2Proof.DlogProof.FirstMessage createDlogProof(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) {
//
// BigInteger r = encryptor.generateRandomExponent(rand);
// ECPoint gr = group.multiply(statement.g, r);
// ECPoint hr = group.multiply(statement.h, r);
//
// Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder()
// .setGr(group.encode(gr))
// .setHr(group.encode(hr))
// .build();
//
// BigInteger challenge = Prover.hash()
// }
//
//
//
//
// /**
// * Generate a ZK proof that there exists x s.t (g ^ x == a and h ^ x == b) or (g' ^ x == a and h' ^ x == b).
// *
// * For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g}(a)==log_{g}(b)):
// * <ol>
// * <li>Prover chooses a random r, and sends g^r, h^r </li>
// * <li>Verifier chooses a random c and sends c</li>
// * <li>Prover computes </li>
// * </ol>
// *
// *
// * @param orStatement
// * @return ZKP OrProof:
// * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs
// */
// private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) {
//
// ECPoint g1 = orStatement.g1;
// ECPoint h1 = orStatement.h1;
// ECPoint g2 = orStatement.g2;
// ECPoint h2 = orStatement.h2;
//
// ECPoint g1Tag = orStatement.g1Tag;
// ECPoint h1Tag = orStatement.h1Tag;
// ECPoint g2Tag = orStatement.g2Tag;
// ECPoint h2Tag = orStatement.h2Tag;
//
// // Randomness for the ZK proof
// BigInteger r = encryptor.generateRandomExponent(rand);
//
//
// BigInteger c1,c2,z,zTag;
// ECPoint u,v,uTag,vTag;
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
//
//
// switch (orStatement.trueClauseIndex) {
// case left:
// c2 = encryptor.generateRandomExponent(rand);
// zTag = encryptor.generateRandomExponent(rand);
// //step 1
// u = group.multiply(g1, r);
// v = group.multiply(g2, r);
// uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2)));
// vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2)));
// //step 2
// // c1 = (hash(input + step1) + group size - c2)% group size
// firstMessage =
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
// .setG1(orStatement.g1Encoded)
// .setH1(orStatement.h1Encoded)
// .setG2(orStatement.g2Encoded)
// .setH2(orStatement.h2Encoded)
// .setG1Tag(orStatement.g1TagEncoded)
// .setH1Tag(orStatement.h1TagEncoded)
// .setG2Tag(orStatement.g2TagEncoded)
// .setH2Tag(orStatement.h2TagEncoded)
// .setU(encryptor.encodeElement(u))
// .setV(encryptor.encodeElement(v))
// .setUTag(encryptor.encodeElement(uTag))
// .setVTag(encryptor.encodeElement(vTag))
// .build();
// c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
// //step 3
// //z = (r + c1 * x) % group size;
// z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
// break;
// case right:
// c1 = encryptor.generateRandomExponent(rand);
// z = encryptor.generateRandomExponent(rand);
// //step 1
// uTag = group.multiply(g1Tag, r);
// vTag = group.multiply(g2Tag, r);
// u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1)));
// v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1)));
// //step 2
// // c1 = (hash(input + step1) + group size - c1)% group size
// firstMessage =
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
// .setG1(orStatement.g1Encoded)
// .setH1(orStatement.h1Encoded)
// .setG2(orStatement.g2Encoded)
// .setH2(orStatement.h2Encoded)
// .setG1Tag(orStatement.g1TagEncoded)
// .setH1Tag(orStatement.h1TagEncoded)
// .setG2Tag(orStatement.g2TagEncoded)
// .setH2Tag(orStatement.h2TagEncoded)
// .setU(encryptor.encodeElement(u))
// .setV(encryptor.encodeElement(v))
// .setUTag(encryptor.encodeElement(uTag))
// .setVTag(encryptor.encodeElement(vTag))
// .build();
// c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
// //step 3
// //zTag = (r + c2 * x) % group size;
// zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
// break;
// default:
// return null;
// }
//
//
// return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
// .setG1(firstMessage.getG1())
// .setH1(firstMessage.getH1())
// .setG2(firstMessage.getG2())
// .setH2(firstMessage.getH2())
// .setG1Tag(firstMessage.getG1())
// .setH1Tag(firstMessage.getH1Tag())
// .setG2Tag(firstMessage.getG2Tag())
// .setH2Tag(firstMessage.getH2Tag())
// .setU(firstMessage.getU())
// .setV(firstMessage.getV())
// .setUTag(firstMessage.getUTag())
// .setVTag(firstMessage.getVTag())
// .setC1(Util.encodeBigInteger(c1))
// .setC2(Util.encodeBigInteger(c2))
// .setZ(Util.encodeBigInteger(z))
// .setZTag(Util.encodeBigInteger(zTag))
// .build();
// }
}

View File

@ -0,0 +1,123 @@
package meerkat.mixer.proofs;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Mixing;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import java.math.BigInteger;
import java.util.Random;
/**
* Schnorr's ZK proof of Dlog equivlance
*/
public class SchnorrDlogEquivalence {
public static class Verifier implements SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
ECElGamalEncryption encryptor;
ECGroup group;
final ECElGamalMixStatementGenerator.DlogStatement statement;
public Verifier(ECElGamalEncryption encryptor, ECElGamalMixStatementGenerator.DlogStatement statement) {
this.encryptor = encryptor;
group = encryptor.getGroup();
this.statement = statement;
}
@Override
public boolean verify(Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage, BigInteger challenge,
Mixing.Mix2Proof.DlogProof.FinalMessage finalMessage) {
ConcreteCrypto.GroupElement grEncoded = firstMessage.getGr();
ECPoint gr = encryptor.decodeElement(grEncoded);
ConcreteCrypto.GroupElement hrEncoded = firstMessage.getHr();
ECPoint hr = encryptor.decodeElement(hrEncoded);
BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr());
boolean gGood = group.add(gr, group.multiply(statement.a, challenge)).equals(group.multiply(statement.g, xcr));
boolean hGood = group.add(hr, group.multiply(statement.b, challenge)).equals(group.multiply(statement.h, xcr));
return gGood && hGood;
}
}
public static class Simulator implements SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
ECElGamalEncryption encryptor;
ECGroup group;
Random rand;
ECElGamalMixStatementGenerator.DlogStatement statement;
BigInteger response = null;
public Simulator(ECElGamalEncryption encryptor, Random rand, ECElGamalMixStatementGenerator.DlogStatement statement) {
this.encryptor = encryptor;
group = encryptor.getGroup();
this.rand = rand;
this.statement = statement;
}
@Override
public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage(BigInteger challenge) {
response = encryptor.generateRandomExponent(rand);
ECPoint u = group.multiply(statement.g, response).subtract(group.multiply(statement.a, challenge));
ECPoint v = group.multiply(statement.h, response).subtract(group.multiply(statement.b, challenge));
return Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder()
.setGr(encryptor.encodeElement(u))
.setHr(encryptor.encodeElement(v))
.build();
}
@Override
public Mixing.Mix2Proof.DlogProof.FinalMessage getFinalMessage() {
return Mixing.Mix2Proof.DlogProof.FinalMessage.newBuilder()
.setXcr(Util.encodeBigInteger(response))
.build();
}
}
public static class Prover implements SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
ECElGamalEncryption encryptor;
ECGroup group;
Random rand;
ECElGamalMixStatementGenerator.DlogStatement statement;
ECElGamalMixStatementGenerator.DlogStatementWitness witness;
BigInteger r = null;
public Prover(ECElGamalEncryption encryptor, Random rand,
ECElGamalMixStatementGenerator.DlogStatement statement, ECElGamalMixStatementGenerator.DlogStatementWitness witness) {
this.encryptor = encryptor;
group = encryptor.getGroup();
this.rand = rand;
this.statement = statement;
this.witness = witness;
}
@Override
public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage() {
r = encryptor.generateRandomExponent(rand);
ECPoint gr = group.multiply(statement.g, r);
ECPoint hr = group.multiply(statement.h, r);
Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder()
.setGr(encryptor.encodeElement(gr))
.setHr(encryptor.encodeElement(hr))
.build();
return firstMessage;
}
@Override
public Mixing.Mix2Proof.DlogProof.FinalMessage getFinalMessage(BigInteger challenge) {
return Mixing.Mix2Proof.DlogProof.FinalMessage.newBuilder()
.setXcr(Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound())))
.build();
}
}
}

View File

@ -12,23 +12,11 @@ public interface SigmaProtocol {
public interface Prover <FirstMsgType, FinalMessageType> {
public FirstMsgType getFirstMessage();
public FinalMessageType getFinalMessage(BigInteger challenge);
/**
* Reset the prover (so the next calls to {@link #getFirstMessage()} will
* start a new proof.
*/
public void reset();
}
public interface Simulator <FirstMsgType, FinalMessageType> {
public FirstMsgType getFirstMessage(BigInteger challenge);
public FinalMessageType getFinalMessage();
/**
* Reset the prover (so the next calls to {@link #getFirstMessage(BigInteger)} will
* start a new proof.
*/
public void reset();
}
public interface Verifier <FirstMsgType, FinalMessageType> {

View File

@ -29,10 +29,6 @@ public class SigmaProtocolAnd2 {
public FinalMessageOut getFinalMessage(BigInteger challenge) {
return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(challenge));
}
@Override
public void reset() { provers[0].reset(); provers[1].reset(); }
}
static public class Verifier<FirstMessageOut, FirstMessageIn,
@ -80,8 +76,6 @@ public class SigmaProtocolAnd2 {
return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
}
@Override
public void reset() { simulators[0].reset(); simulators[1].reset(); }
}
}

View File

@ -72,9 +72,6 @@ public class SigmaProtocolOr2 {
return finalMessageConcatenator.concatenate(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge));
}
}
@Override
public void reset() { prover.reset(); simulator.reset(); simChallenge = null; }
}
static public class Verifier <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
@ -142,9 +139,6 @@ public class SigmaProtocolOr2 {
public FinalMessageOut getFinalMessage() {
return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
}
@Override
public void reset() { simulators[0].reset(); simulators[1].reset(); }
}
}

View File

@ -8,7 +8,6 @@ import meerkat.protobuf.Mixing;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
/**
* implements Mix2ZeroKnowledgeVerifier
@ -16,11 +15,11 @@ import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
public class Verifier implements Mix2ZeroKnowledgeVerifier {
private final ECElGamalEncryption encryptor;
private final ECGroup group;
private final RandomOracle randomOracle;
private final ECPoint g,h;
private final ECElGamalMixParams mixParams;
final ECElGamalMixProtocols mixProtocols;
private final ECElGamalMixStatementGenerator mixParams;
final SigmaFiatShamir mix2NIZK;
@ -32,12 +31,12 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
* @param randomOracle should be as the random oracle used by meerkat.mixer.proofs
*/
public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) {
this.encryptor = encryptor;
this.group = encryptor.getGroup();
this.g = group.getGenerator();
this.h = encryptor.getElGamalPK().getPK();
this.randomOracle = randomOracle;
this.mixParams = new ECElGamalMixParams(encryptor);
this.mixProtocols = new ECElGamalMixProtocols(mixParams, null); // We don't need randomness for the verifier
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
// this.parser = new ZeroKnowledgeOrProofParser(group);
}
@ -60,8 +59,8 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
Crypto.RerandomizableEncryptedMessage out2,
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException {
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
Mix2Verifier verifier = mixProtocols.new Mix2Verifier(statement);
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
Mix2.Verifier verifier = new Mix2.Verifier(encryptor, statement);
return mix2NIZK.verifyNizk(proof, verifier);
}

View File

@ -16,20 +16,17 @@ public final class VerifyTable {
/**
* constructor
* @param verifier
* @param n
* @param mixerOutput
* @return true iff the meerkat.mixer.mixing output is valid
* @throws InvalidProtocolBufferException
*/
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput)
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier, MixerOutput mixerOutput)
throws InvalidProtocolBufferException {
int index1,index2,layer;
int out0,out1,layer, switchIdx;
//assert n = 2^k
if ( (n &(n-1)) != 0)
throw new IllegalArgumentException("n");
int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1;
int layers = mixerOutput.getNumLayers();
int n = 1 << mixerOutput.getLogN();
//initialize locationChecksum table
// use for check BeneshNet validity
boolean[][] locationChecksum = new boolean[layers][n];
@ -44,36 +41,32 @@ public final class VerifyTable {
for (int j = 0; j < Mix2Proofs[i].length ; j ++){
Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
Mixing.Mix2Proof.Location location = zkp.getLocation();
index1 = location.getI();
index2 = location.getJ();
out0 = location.getOut0();
out1 = location.getOut1();
layer = location.getLayer();
switchIdx = location.getSwitchIdx();
// check location validity
if (layer > layers >> 1) {
if (index2 - index1 != n >> (layers - layer))
return false;
}
else{
if (index2 - index1 != n >> (layer + 1))
return false;
}
// TODO: add check
// if (layer > layers >> 1) {
// if (out1 - out0 != n >> (layers - layer))
// return false;
// }
// else{
// if (out1 - out0 != n >> (layer + 1))
// return false;
// }
// mark location in table
locationChecksum[layer][index1] = true;
locationChecksum[layer][index2] = true;
locationChecksum[layer][2 * switchIdx] = true;
locationChecksum[layer][2 * switchIdx + 1] = true;
// verify proof
if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1],
rerandomizableEncryptedMessages[layer][index2],
rerandomizableEncryptedMessages[layer + 1][index1],
rerandomizableEncryptedMessages[layer + 1][index2],
if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx],
rerandomizableEncryptedMessages[layer][2 * switchIdx + 1],
rerandomizableEncryptedMessages[layer + 1][out0],
rerandomizableEncryptedMessages[layer + 1][out1],
zkp)) {
verifier.verify(rerandomizableEncryptedMessages[layer][index1],
rerandomizableEncryptedMessages[layer][index2],
rerandomizableEncryptedMessages[layer + 1][index1],
rerandomizableEncryptedMessages[layer + 1][index2],
zkp);
return false;
}
}

View File

@ -7,6 +7,11 @@ option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
import 'meerkat/concrete_crypto.proto';
message MixBatchHeader {
int32 logN = 1; // log (base 2) of number of inputs to mix
int32 layers = 2; // Number of layers in mix
}
message Plaintext {
bytes data = 1;
}
@ -44,13 +49,19 @@ message Mix2Proof {
BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0
}
message Location{
int32 i = 1;
int32 j = 2;
int32 layer = 3;
// Location of the
message Location {
int32 layer = 1; // layer in which the switch is placed
int32 switchIdx = 2; // idx of the switch
int32 out0 = 3; // idx of the first output ciphertext (in layer+1 of the ciphertext matrix)
int32 out1 = 4; // idx of the second output ciphertext (in layer+1 of the ciphertext matrix)
}
FirstMessage firstMessage = 1;
FinalMessage finalMessage = 2;
Location location = 5;
}

View File

@ -1,100 +1,100 @@
package meerkat.mixer;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
import meerkat.mixer.mixing.Mixer;
import meerkat.mixer.mixing.MixerOutput;
import meerkat.mixer.proofs.Prover;
import meerkat.mixer.proofs.Verifier;
import meerkat.mixer.proofs.VerifyTable;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting;
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.DigestOracle;
import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.junit.Before;
import java.io.IOException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by Tzlil on 1/19/2016.
*/
public class CreateTestVector {
ECElGamalEncryption encryptor;
ECGroup group;
Random random,randomMixer,randomProver;
RandomOracle randomOracle;
Mix2ZeroKnowledgeVerifier verifier;
Mix2ZeroKnowledgeProver prover;
meerkat.crypto.mixnet.Mixer mixer;
private int layers;
private int n;
@Before
public void setup() throws InvalidKeySpecException {
// initialization
random = new Random();
group = new ECGroup("secp256k1");
encryptor = new ECElGamalEncryption();
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
randomMixer = new Random();
randomProver = new Random();
randomOracle = new DigestOracle();
verifier = new Verifier(encryptor,randomOracle);
prover = new Prover(randomProver,encryptor,randomOracle);
mixer = new Mixer(prover,encryptor);
// generate n
int logN = 10; // + random.nextInt(8)
layers = 2*logN - 1;
n = 1 << logN;
}
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
Voting.PlaintextBallot msg;
for (int i = 0; i < n ; i++){
msg = Utils.genRandomBallot(2,3,16);
result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
}
return result;
}
//@SimpleRerandomizeTest
public void createValidTest() throws IOException {
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
System.out.println("start mixing");
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
System.out.println("mixing ended, start verification");
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
System.out.println("verification ended, start printing");
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
System.out.println("all done");
}
//@SimpleRerandomizeTest
public void createInvalidTest() throws IOException {
//Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
//Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
//mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
System.out.println("start mixing");
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
System.out.println("mixing ended, start negative verification");
assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
System.out.println("verification ended, start printing");
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
System.out.println("all done");
}
}
//package meerkat.mixer;
//
//import meerkat.crypto.concrete.ECElGamalEncryption;
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
//import meerkat.mixer.mixing.Mixer;
//import meerkat.mixer.mixing.MixerOutput;
//import meerkat.mixer.proofs.Prover;
//import meerkat.mixer.proofs.Verifier;
//import meerkat.mixer.proofs.VerifyTable;
//import meerkat.protobuf.Crypto;
//import meerkat.protobuf.Voting;
//import org.factcenter.qilin.primitives.RandomOracle;
//import org.factcenter.qilin.primitives.concrete.DigestOracle;
//import org.factcenter.qilin.primitives.concrete.ECElGamal;
//import org.factcenter.qilin.primitives.concrete.ECGroup;
//import org.junit.Before;
//
//import java.io.IOException;
//import java.security.spec.InvalidKeySpecException;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Random;
//
///**
// * Created by Tzlil on 1/19/2016.
// */
//public class CreateTestVector {
//
//
// ECElGamalEncryption encryptor;
// ECGroup group;
// Random random,randomMixer,randomProver;
// RandomOracle randomOracle;
// Mix2ZeroKnowledgeVerifier verifier;
// Mix2ZeroKnowledgeProver prover;
// meerkat.crypto.mixnet.Mixer mixer;
// private int layers;
// private int n;
//
//
// @Before
// public void setup() throws InvalidKeySpecException {
// // initialization
// random = new Random();
// group = new ECGroup("secp256k1");
// encryptor = new ECElGamalEncryption();
// encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// randomMixer = new Random();
// randomProver = new Random();
// randomOracle = new DigestOracle();
// verifier = new Verifier(encryptor,randomOracle);
// prover = new Prover(randomProver,encryptor,randomOracle);
// mixer = new Mixer(prover,encryptor);
//
// // generate n
// int logN = 10; // + random.nextInt(8)
// layers = 2*logN - 1;
// n = 1 << logN;
// }
//
// public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
// List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
// Voting.PlaintextBallot msg;
// for (int i = 0; i < n ; i++){
// msg = Utils.genRandomBallot(2,3,16);
// result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
// }
// return result;
// }
// //@SimpleRerandomizeTest
// public void createValidTest() throws IOException {
//
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
// System.out.println("start mixing");
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
// System.out.println("mixing ended, start verification");
// assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
// System.out.println("verification ended, start printing");
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
// System.out.println("all done");
// }
//
// //@SimpleRerandomizeTest
// public void createInvalidTest() throws IOException {
//
// //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
// //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
// //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
//
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
// System.out.println("start mixing");
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
// System.out.println("mixing ended, start negative verification");
// assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
// System.out.println("verification ended, start printing");
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
// System.out.println("all done");
// }
//}

View File

@ -77,7 +77,7 @@ public class Mix2ProofTest extends ECParamTestBase {
group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));
Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2);
Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0, 0, r1,r2);
assertTrue (verifier.verify(e1,e2,e1New,e2New, proof));
}

View File

@ -1,46 +0,0 @@
package meerkat.mixer;
/**
* Created by Tzlil on 12/17/2015.
*/
import meerkat.mixer.mixing.MixNetwork;
import meerkat.mixer.mixing.RandomPermutation;
import meerkat.mixer.mixing.Switch;
import org.junit.Test;
import java.util.Arrays;
import java.util.Random;
public class MixNetworkTest {
@Test
public void testMixNetwork() throws Exception{
Random random = new Random(1);
int logn = 10;
int n = 1 << logn;
int layers = 2*logn - 1;
RandomPermutation randomPermutation = new RandomPermutation(n,random);
MixNetwork mixNetwork = new MixNetwork(randomPermutation);
//initialize arr s.t arr[i] = i
int[] arr = new int[n];
for (int i = 0; i < n ;i ++)
arr[i] = i;
// layer by layer swap between values
for (int layer = 0 ; layer< layers ; layer ++) {
for (Switch sw : mixNetwork.getSwitchesByLayer(layer)) {
if(sw.value) {
arr[sw.i] += arr[sw.j];
arr[sw.j] = arr[sw.i] - arr[sw.j];
arr[sw.i] -= arr[sw.j];
}
}
}
assert(Arrays.equals(arr,randomPermutation.permutation));
}
}

View File

@ -45,7 +45,7 @@ public class MixingTest extends ECParamTestBase {
mixer = new Mixer(prover, enc);
// generate n
int logN = 9; // + random.nextInt(8)
int logN = 5; // + random.nextInt(8)
layers = 2*logN - 1;
n = 1 << logN;
}
@ -76,7 +76,7 @@ public class MixingTest extends ECParamTestBase {
System.out.println("start verification");
startTime = System.currentTimeMillis();
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
assert (VerifyTable.verifyTable(verifier,mixerOutput));
finishTime = System.currentTimeMillis();
System.out.println(" that took: "+(finishTime-startTime)+ " ms");

View File

@ -11,8 +11,8 @@ import java.math.BigInteger;
public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
final DlogStatementSchnorrSigmaTest dlogtest;
ECElGamalMixParams.DlogStatement s1, s2;
ECElGamalMixParams.DlogStatementWitness w1, w2;
ECElGamalMixStatementGenerator.DlogStatement s1, s2;
ECElGamalMixStatementGenerator.DlogStatementWitness w1, w2;
public DlogAndStatementSigmaTest() {
this.dlogtest = new DlogStatementSchnorrSigmaTest();
@ -20,10 +20,10 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
@Override
void generateRandomTrueStatement() {
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
s1 = s1w1.a; w1 = s1w1.b;
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
s2 = s2w2.a; w2 = s2w2.b;
}
@ -36,19 +36,19 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
@Override
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
return new SigmaProtocolAnd2.Prover<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
dlogtest.prots.new DlogStatementSchnorrProver(s1, w1), dlogtest.prots.new DlogStatementSchnorrProver(s2, w2));
new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s1, w1), new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s2, w2));
}
@Override
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewVerifier() {
return new SigmaProtocolAnd2.Verifier<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
dlogtest.prots.new DlogStatementSchnorrVerifier(s1), dlogtest.prots.new DlogStatementSchnorrVerifier(s2));
new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s1), new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s2));
}
@Override
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewSimulator() {
return new SigmaProtocolAnd2.Simulator<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
dlogtest.prots.new DlogStatementSchnorrSimulator(s1), dlogtest.prots.new DlogStatementSchnorrSimulator(s2));
new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s1), new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s2));
}
@Override

View File

@ -11,8 +11,8 @@ import java.math.BigInteger;
public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> {
final DlogStatementSchnorrSigmaTest dlogtest;
final ECElGamalMixParams.AndStatement[] statements = new ECElGamalMixParams.AndStatement[2];
ECElGamalMixParams.AndStatementWitness w;
final ECElGamalMixStatementGenerator.AndStatement[] statements = new ECElGamalMixStatementGenerator.AndStatement[2];
ECElGamalMixStatementGenerator.AndStatementWitness w;
int trueStatementIndex;
@ -23,53 +23,57 @@ public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof
@Override
void generateRandomTrueStatement() {
trueStatementIndex = rand.nextInt(2);
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
ECElGamalMixParams.AndStatement trueStatement = dlogtest.params.new AndStatement(s1w1.a, s2w2.a);
w = dlogtest.params.new AndStatementWitness(s1w1.b, s2w2.b);
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
ECElGamalMixStatementGenerator.AndStatement trueStatement = dlogtest.statementGenerator.new AndStatement(s1w1.a, s2w2.a);
w = dlogtest.statementGenerator.new AndStatementWitness(s1w1.b, s2w2.b);
statements[trueStatementIndex] = trueStatement;
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
ECElGamalMixParams.AndStatement falseStatement = dlogtest.params.new AndStatement(f1, f2);
ECElGamalMixStatementGenerator.AndStatement falseStatement = dlogtest.statementGenerator.new AndStatement(f1, f2);
statements[1 - trueStatementIndex] = falseStatement;
}
@Override
void generateRandomFalseStatement() {
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
statements[0] = dlogtest.params.new AndStatement(f1, f2);
statements[0] = dlogtest.statementGenerator.new AndStatement(f1, f2);
f1 = dlogtest.returnRandomFalseStatement();
f2 = dlogtest.returnRandomFalseStatement();
statements[1] = dlogtest.params.new AndStatement(f1, f2);
statements[1] = dlogtest.statementGenerator.new AndStatement(f1, f2);
}
@Override
protected SigmaProtocol.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewProver() {
SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andProver = dlogtest.prots.new AndStatementProver(statements[trueStatementIndex], w);
SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andSimulator = dlogtest.prots.new AndStatementSimulator(statements[1 - trueStatementIndex]);
SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andProver = new DlogConjunction.Prover(dlogtest.encryptor, rand, statements[trueStatementIndex], w);
SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andSimulator = new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1 - trueStatementIndex]);
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
return new SigmaProtocolOr2.Prover<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
dlogtest.prots.challengeGenerator, andProver, andSimulator, trueStatementIndex);
gen, andProver, andSimulator, trueStatementIndex);
}
@Override
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewVerifier() {
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
return new SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage,
Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementVerifier(statements[0]), dlogtest.prots.new AndStatementVerifier(statements[1]));
gen, new DlogConjunction.Verifier(dlogtest.encryptor, statements[0]), new DlogConjunction.Verifier(dlogtest.encryptor, statements[1]));
}
@Override
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewSimulator() {
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
return new SigmaProtocolOr2.Simulator<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementSimulator(statements[0]),
dlogtest.prots.new AndStatementSimulator(statements[1]));
gen, new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[0]),
new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1]));
}
@Override

View File

@ -1,8 +1,10 @@
package meerkat.mixer.proofs;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.ECParamTestBase;
import meerkat.protobuf.Mixing;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.factcenter.qilin.util.Pair;
import java.math.BigInteger;
@ -13,42 +15,44 @@ import java.math.BigInteger;
public class DlogStatementSchnorrSigmaTest extends
SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
ECParamTestBase ecParams = new ECParamTestBase();
ECElGamalMixParams params;
ECElGamalMixProtocols prots;
ECParamTestBase ecParams;
ECElGamalMixStatementGenerator statementGenerator;
ECElGamalEncryption encryptor;
ECGroup group;
ECElGamalMixParams.DlogStatement statement;
ECElGamalMixParams.DlogStatementWitness witness;
ECElGamalMixProtocols.DlogStatementSchnorrProver prover;
ECElGamalMixProtocols.DlogStatementSchnorrVerifier verifier;
ECElGamalMixProtocols.DlogStatementSchnorrSimulator simulator;
ECElGamalMixStatementGenerator.DlogStatement statement;
ECElGamalMixStatementGenerator.DlogStatementWitness witness;
SchnorrDlogEquivalence.Prover prover;
SchnorrDlogEquivalence.Verifier verifier;
SchnorrDlogEquivalence.Simulator simulator;
public DlogStatementSchnorrSigmaTest() {
this.params = new ECElGamalMixParams(ecParams.enc);
this.prots = new ECElGamalMixProtocols(params, rand); // We don't need randomness for the verifier
ecParams = new ECParamTestBase();
encryptor = ecParams.enc;
group = encryptor.getGroup();
this.statementGenerator = new ECElGamalMixStatementGenerator(ecParams.enc);
}
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> returnRandomTrueStatement() {
BigInteger x = prots.encryptor.generateRandomExponent(rand);
ECPoint a = prots.group.multiply(prots.g, x);
ECPoint b = prots.group.multiply(prots.h, x);
ECElGamalMixParams.DlogStatement statement = params.new DlogStatement(a, b);
ECElGamalMixParams.DlogStatementWitness witness = params.new DlogStatementWitness(x);
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> returnRandomTrueStatement() {
BigInteger x = encryptor.generateRandomExponent(rand);
ECPoint a = group.multiply(statementGenerator.g, x);
ECPoint b = group.multiply(statementGenerator.h, x);
ECElGamalMixStatementGenerator.DlogStatement statement = statementGenerator.new DlogStatement(a, b);
ECElGamalMixStatementGenerator.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x);
return new Pair<>(statement, witness);
}
ECElGamalMixParams.DlogStatement returnRandomFalseStatement() {
ECPoint a = prots.group.sample(rand);
ECPoint b = prots.group.sample(rand);
ECElGamalMixStatementGenerator.DlogStatement returnRandomFalseStatement() {
ECPoint a = group.sample(rand);
ECPoint b = group.sample(rand);
return params.new DlogStatement(a, b);
return statementGenerator.new DlogStatement(a, b);
}
void generateRandomTrueStatement() {
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> sw = returnRandomTrueStatement();
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> sw = returnRandomTrueStatement();
this.statement = sw.a;
this.witness = sw.b;
}
@ -60,24 +64,24 @@ public class DlogStatementSchnorrSigmaTest extends
@Override
protected SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
prover = prots.new DlogStatementSchnorrProver(statement, witness);
prover = new SchnorrDlogEquivalence.Prover(encryptor, rand, statement, witness);
return prover;
}
@Override
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
verifier = prots.new DlogStatementSchnorrVerifier(statement);
verifier = new SchnorrDlogEquivalence.Verifier(encryptor, statement);
return verifier;
}
@Override
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewSimulator() {
simulator = prots.new DlogStatementSchnorrSimulator(statement);
simulator = new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement);
return simulator;
}
@Override
protected BigInteger getChallengeModulus() {
return prots.group.orderUpperBound();
return group.orderUpperBound();
}
}

View File

@ -34,11 +34,6 @@ public class DummySigmaProof {
public BigInteger getFinalMessage(BigInteger challenge) {
return challenge.add(r.multiply(x.add(y)));
}
@Override
public void reset() {
}
}
public static class Verifier implements SigmaProtocol.Verifier<Crypto.BigInteger,BigInteger> {
@ -81,11 +76,6 @@ public class DummySigmaProof {
public BigInteger getFinalMessage() {
return resp;
}
@Override
public void reset() {
}
}
}

View File

@ -75,7 +75,7 @@ public class ZeroKnowledgeProof {
for (int i = 0; i < n*2 ; i +=2){
prover.prove(encryptedMessage[i],encryptedMessage[i+1],reencryptedMessage[i],reencryptedMessage[i+1],
false,0,0,0,randomnesses[i],randomnesses[i+1]);
false,0,0,0, 0, randomnesses[i],randomnesses[i+1]);
}
long finishTime = System.currentTimeMillis();