Refactoring (tests currently fail)
parent
78f823f31e
commit
fc2c26d7e9
|
@ -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;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,5 +9,6 @@ import meerkat.protobuf.Mixing;
|
||||||
public interface MixerOutput {
|
public interface MixerOutput {
|
||||||
public Mixing.Mix2Proof[][] getProofs();
|
public Mixing.Mix2Proof[][] getProofs();
|
||||||
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages();
|
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages();
|
||||||
public int getN();
|
public int getLogN();
|
||||||
|
public int getNumLayers();
|
||||||
}
|
}
|
|
@ -15,37 +15,6 @@ import java.util.List;
|
||||||
* provide convert operation from batch data to meerkat.mixer.mixing output and backwards
|
* provide convert operation from batch data to meerkat.mixer.mixing output and backwards
|
||||||
*/
|
*/
|
||||||
public class BatchConverter {
|
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
|
* convert meerkat.mixer.mixing output to batch data
|
||||||
* @param mixerOutput
|
* @param mixerOutput
|
||||||
|
@ -55,8 +24,13 @@ public class BatchConverter {
|
||||||
|
|
||||||
List<BulletinBoardAPI.BatchChunk> result = new ArrayList<BulletinBoardAPI.BatchChunk>();
|
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()
|
result.add(BulletinBoardAPI.BatchChunk.newBuilder()
|
||||||
.setData(Integer2ByteString(n))
|
.setData(header.toByteString())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) {
|
for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) {
|
||||||
|
@ -85,10 +59,11 @@ public class BatchConverter {
|
||||||
public MixerOutput BatchChunkList2MixerOutput
|
public MixerOutput BatchChunkList2MixerOutput
|
||||||
(List<BulletinBoardAPI.BatchChunk> batchChunkList) throws Exception {
|
(List<BulletinBoardAPI.BatchChunk> batchChunkList) throws Exception {
|
||||||
|
|
||||||
if (n != ByteString2Integer(batchChunkList.remove(0).getData())){
|
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseFrom(batchChunkList.remove(0).getData());
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int logN = header.getLogN();
|
||||||
|
int n = 1 << logN;
|
||||||
|
int layers = header.getLayers();
|
||||||
int nDiv2 = n >>1;
|
int nDiv2 = n >>1;
|
||||||
Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2];
|
Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2];
|
||||||
for (int layer = 0; layer < layers; layer++)
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,14 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
||||||
private Throwable t;
|
private Throwable t;
|
||||||
private CompleteBatch msg;
|
private CompleteBatch msg;
|
||||||
|
|
||||||
private final int n, layers;
|
|
||||||
private final Mix2ZeroKnowledgeVerifier verifier;
|
private final Mix2ZeroKnowledgeVerifier verifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
* @param n
|
|
||||||
* @param layers
|
|
||||||
* @param verifier
|
* @param verifier
|
||||||
*/
|
*/
|
||||||
public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) {
|
public BatchHandler(Mix2ZeroKnowledgeVerifier verifier) {
|
||||||
this.mixerOutput = null;
|
this.mixerOutput = null;
|
||||||
this.n = n;
|
|
||||||
this.layers = layers;
|
|
||||||
this.msgReceived = false;
|
this.msgReceived = false;
|
||||||
this.t = null;
|
this.t = null;
|
||||||
this.verifier = verifier;
|
this.verifier = verifier;
|
||||||
|
@ -70,7 +65,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private void convertMessage() throws Exception {
|
private void convertMessage() throws Exception {
|
||||||
BatchConverter batchConverter = new BatchConverter(n,layers);
|
BatchConverter batchConverter = new BatchConverter();
|
||||||
this.mixerOutput = batchConverter.BatchChunkList2MixerOutput(msg.getBatchChunkList());
|
this.mixerOutput = batchConverter.BatchChunkList2MixerOutput(msg.getBatchChunkList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +78,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
||||||
if (mixerOutput == null) {
|
if (mixerOutput == null) {
|
||||||
convertMessage();
|
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()){
|
if(!verifyTable()){
|
||||||
throw new Exception("in valid table");
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import meerkat.crypto.mixnet.Mixer;
|
||||||
import meerkat.crypto.mixnet.MixerOutput;
|
import meerkat.crypto.mixnet.MixerOutput;
|
||||||
import meerkat.protobuf.BulletinBoardAPI;
|
import meerkat.protobuf.BulletinBoardAPI;
|
||||||
import meerkat.protobuf.Crypto;
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.mixer.mixing.MixNetwork;
|
|
||||||
import meerkat.mixer.necessary.AsyncBulletinBoardClient;
|
import meerkat.mixer.necessary.AsyncBulletinBoardClient;
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +25,6 @@ public class MainMixing {
|
||||||
|
|
||||||
private final Mixer mixer;
|
private final Mixer mixer;
|
||||||
private final Mix2ZeroKnowledgeVerifier verifier;
|
private final Mix2ZeroKnowledgeVerifier verifier;
|
||||||
private final int n, layers;
|
|
||||||
private final AsyncBulletinBoardClient asyncBulletinBoardClient;
|
private final AsyncBulletinBoardClient asyncBulletinBoardClient;
|
||||||
private final byte[] id;
|
private final byte[] id;
|
||||||
|
|
||||||
|
@ -35,16 +33,13 @@ public class MainMixing {
|
||||||
* constructor
|
* constructor
|
||||||
* @param mixer
|
* @param mixer
|
||||||
* @param verifier
|
* @param verifier
|
||||||
* @param n
|
|
||||||
* @param asyncBulletinBoardClient
|
* @param asyncBulletinBoardClient
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n
|
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier,
|
||||||
, AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
|
AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
|
||||||
this.mixer = mixer;
|
this.mixer = mixer;
|
||||||
this.verifier = verifier;
|
this.verifier = verifier;
|
||||||
this.n = n;
|
|
||||||
this.layers = MixNetwork.numberOfLayers(n);
|
|
||||||
this.asyncBulletinBoardClient = asyncBulletinBoardClient;
|
this.asyncBulletinBoardClient = asyncBulletinBoardClient;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +59,7 @@ public class MainMixing {
|
||||||
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
|
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
|
||||||
BatchHandler currentBatchHandler;
|
BatchHandler currentBatchHandler;
|
||||||
for (Integer prevBatchId : prevBatchIds) {
|
for (Integer prevBatchId : prevBatchIds) {
|
||||||
currentBatchHandler = new BatchHandler(n, layers,verifier);
|
currentBatchHandler = new BatchHandler(verifier);
|
||||||
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
|
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
|
||||||
batchHandlers.add(currentBatchHandler);
|
batchHandlers.add(currentBatchHandler);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +94,7 @@ public class MainMixing {
|
||||||
private void updateBB(MixerOutput mixerOutput
|
private void updateBB(MixerOutput mixerOutput
|
||||||
, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) {
|
, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) {
|
||||||
|
|
||||||
BatchConverter batchConverter = new BatchConverter(n,layers);
|
BatchConverter batchConverter = new BatchConverter();
|
||||||
List<BulletinBoardAPI.BatchChunk> batchChunkList = batchConverter.MixerOutput2BatchChunk(mixerOutput);
|
List<BulletinBoardAPI.BatchChunk> batchChunkList = batchConverter.MixerOutput2BatchChunk(mixerOutput);
|
||||||
asyncBulletinBoardClient.postBatch(id, batchId, batchChunkList, callback);
|
asyncBulletinBoardClient.postBatch(id, batchId, batchChunkList, callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -80,89 +80,96 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate new random mix network
|
* generate new random mix network
|
||||||
* @param n number of votes
|
* @param logN log number of votes
|
||||||
* @param random
|
* @param random
|
||||||
* @return new random mix network
|
* @return new random mix network
|
||||||
*/
|
*/
|
||||||
private MixNetwork generateMixNetwork(int n,Random random){
|
private PermutationNetwork generateMixNetwork(int logN, Random random){
|
||||||
return new MixNetwork(new RandomPermutation(n,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.
|
* fills the encryption table with rerandomized encrypted votes.
|
||||||
* @param layers
|
|
||||||
* @param mixNetwork switches table (boolean values)
|
* @param mixNetwork switches table (boolean values)
|
||||||
* @param encryptionTable an initialized encryption table s.t first layer == given encrypted votes
|
* @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
|
* @param randomnesses an initialized randomness table of size layers * n, use for rerandomize operations
|
||||||
* @throws InvalidProtocolBufferException
|
* @throws InvalidProtocolBufferException
|
||||||
*/
|
*/
|
||||||
private void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
|
private void rerandomize(PermutationNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
|
||||||
,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||||
Switch[] switchesLayer;
|
Switch[] switchesLayer;
|
||||||
int index1,index2;
|
int index1,index2;
|
||||||
RerandomizableEncryptedMessage e1,e2;
|
RerandomizableEncryptedMessage a,b;
|
||||||
EncryptionRandomness r1,r2;
|
EncryptionRandomness r1,r2;
|
||||||
for (int layer = 0; layer < layers; layer++)
|
int layers = mixNetwork.getNumLayers();
|
||||||
{
|
|
||||||
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];
|
int numSwitches = mixNetwork.getNumInputs() >>> 1;
|
||||||
r2 = randomnesses[layer][index2];
|
|
||||||
if (!sw.value) {
|
|
||||||
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1);
|
|
||||||
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2);
|
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2);
|
encryptionTable[layer + 1][out0] = encryptor.rerandomize(a, r1);
|
||||||
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1);
|
encryptionTable[layer + 1][out1] = encryptor.rerandomize(b, r2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate zero knowledge proof for each rerandomize encrypted votes couple in encryptionTable
|
* 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 mixNetwork switches table (boolean values) used for set encryption table
|
||||||
* @param encryptionTable full encryption table
|
* @param encryptionTable full encryption table
|
||||||
* @param randomnesses randomness table of size layers * n, used for set encryption table
|
* @param randomnesses randomness table of size layers * n, used for set encryption table
|
||||||
* @return zero knowledge proofs table
|
* @return zero knowledge proofs table
|
||||||
* @throws InvalidProtocolBufferException
|
* @throws InvalidProtocolBufferException
|
||||||
*/
|
*/
|
||||||
private Mix2Proof[][] generateMix2ProofTable(int n, int layers, MixNetwork mixNetwork
|
private Mix2Proof[][] generateMix2ProofTable(PermutationNetwork mixNetwork
|
||||||
, RerandomizableEncryptedMessage[][] encryptionTable
|
, RerandomizableEncryptedMessage[][] encryptionTable
|
||||||
, EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
, EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||||
|
int layers = mixNetwork.getNumLayers();
|
||||||
|
int n = mixNetwork.getNumInputs();
|
||||||
Switch[] switchesLayer;
|
Switch[] switchesLayer;
|
||||||
int index1,index2;
|
int index1,index2;
|
||||||
int switchIndex = 0;
|
int switchIndex = 0;
|
||||||
int nDiv2 = n >> 1;
|
int numSwitches = n >> 1;
|
||||||
Mix2Proof[][] proofsTable = new Mix2Proof[layers][nDiv2];
|
Mix2Proof[][] proofsTable = new Mix2Proof[layers][numSwitches];
|
||||||
|
|
||||||
RerandomizableEncryptedMessage e1,e2;
|
RerandomizableEncryptedMessage a,b,c,d;
|
||||||
EncryptionRandomness r1,r2;
|
EncryptionRandomness r1,r2;
|
||||||
for (int layer = 0; layer < layers; layer++)
|
for (int layer = 0; layer < layers; layer++) {
|
||||||
{
|
for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) {
|
||||||
switchesLayer = mixNetwork.getSwitchesByLayer(layer);
|
boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx);
|
||||||
for (Switch sw : switchesLayer) {
|
int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx);
|
||||||
index1 = sw.i;
|
int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
|
||||||
index2 = sw.j;
|
|
||||||
e1 = encryptionTable[layer][index1];
|
a = encryptionTable[layer][2 * switchIdx];
|
||||||
e2 = encryptionTable[layer][index2];
|
b = encryptionTable[layer][2 * switchIdx + 1];
|
||||||
r1 = randomnesses[layer][index1];
|
c = encryptionTable[layer + 1][out0];
|
||||||
r2 = randomnesses[layer][index2];
|
d = encryptionTable[layer + 1][out1];
|
||||||
|
r1 = randomnesses[layer][2 * switchIdx];
|
||||||
|
r2 = randomnesses[layer][2 * switchIdx + 1];
|
||||||
|
|
||||||
proofsTable[layer][switchIndex] =
|
proofsTable[layer][switchIndex] =
|
||||||
prover.prove(e1, e2, encryptionTable[layer + 1][index1],
|
prover.prove(a, b, c, d, isCrossed, layer, switchIdx, out0, out1, r1, r2);
|
||||||
encryptionTable[layer + 1][index2],
|
|
||||||
sw.value, sw.i, sw.j, sw.layer, r1, r2);
|
|
||||||
|
|
||||||
switchIndex = (switchIndex + 1) % nDiv2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return proofsTable;
|
return proofsTable;
|
||||||
|
@ -180,14 +187,18 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
||||||
int n = ciphertexts.size();
|
int n = ciphertexts.size();
|
||||||
assert (n > 1 && isPowerOfTwo(n));
|
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);
|
RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts);
|
||||||
EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,23 +16,20 @@ import java.io.IOException;
|
||||||
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput {
|
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput {
|
||||||
private final Mixing.Mix2Proof[][] proofs;
|
private final Mixing.Mix2Proof[][] proofs;
|
||||||
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
|
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
|
||||||
private final int n;
|
private final int logN;
|
||||||
private final int layers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
* @param n number of votes
|
* @param logN log (base 2) of the number of votes
|
||||||
* @param layers
|
|
||||||
* @param encryptedMessages at level 0 , contains the original encrypted votes
|
* @param encryptedMessages at level 0 , contains the original encrypted votes
|
||||||
* at each other level contains the re encrypted votes
|
* at each other level contains the re encrypted votes
|
||||||
* @param proofs in each cell (level,switch) contains the match zero knowledge proof
|
* @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) {
|
, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
|
||||||
this.proofs = proofs;
|
this.proofs = proofs;
|
||||||
this.encryptedMessages = encryptedMessages;
|
this.encryptedMessages = encryptedMessages;
|
||||||
this.n = n;
|
this.logN = logN;
|
||||||
this.layers = layers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,8 +45,13 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getN() {
|
public int getLogN() {
|
||||||
return n;
|
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
|
* @param dir - directory
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void outToFolder(String dir) throws IOException {
|
// public void outToFolder(String dir) throws IOException {
|
||||||
|
//
|
||||||
(new File(dir)).mkdirs();
|
// (new File(dir)).mkdirs();
|
||||||
//create files
|
// //create files
|
||||||
String proofsDir = dir + "/Proofs";
|
// String proofsDir = dir + "/Proofs";
|
||||||
String encDir = dir + "/EncryptedMessages";
|
// String encDir = dir + "/EncryptedMessages";
|
||||||
(new File(proofsDir)).mkdir();
|
// (new File(proofsDir)).mkdir();
|
||||||
(new File(encDir)).mkdir();
|
// (new File(encDir)).mkdir();
|
||||||
for (int layer = 0; layer < layers; layer++){
|
// for (int layer = 0; layer < layers; layer++){
|
||||||
(new File(proofsDir +"/layer" + layer )).mkdir();
|
// (new File(proofsDir +"/layer" + layer )).mkdir();
|
||||||
(new File(encDir +"/layer" + layer )).mkdir();
|
// (new File(encDir +"/layer" + layer )).mkdir();
|
||||||
}
|
// }
|
||||||
(new File(encDir +"/input")).mkdir();
|
// (new File(encDir +"/input")).mkdir();
|
||||||
|
//
|
||||||
|
//
|
||||||
for (int layer = 0; layer < layers; layer++){
|
// for (int layer = 0; layer < layers; layer++){
|
||||||
for(int i = 0; i < proofs[layer].length; i ++){
|
// for(int i = 0; i < proofs[layer].length; i ++){
|
||||||
writeProofToFile(proofsDir,proofs[layer][i]);
|
// writeProofToFile(proofsDir,proofs[layer][i]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for (int layer = 0; layer <= layers; layer++){
|
// for (int layer = 0; layer <= layers; layer++){
|
||||||
for(int i = 0; i < encryptedMessages[layer].length; i ++){
|
// for(int i = 0; i < encryptedMessages[layer].length; i ++){
|
||||||
writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
|
// writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create new file contains single proof
|
* create new file contains single proof
|
||||||
|
@ -91,19 +93,19 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
||||||
* @param proof
|
* @param proof
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
|
// private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
|
||||||
Mixing.Mix2Proof.Location location = proof.getLocation();
|
// Mixing.Mix2Proof.Location location = proof.getLocation();
|
||||||
int layer = location.getLayer();
|
// int layer = location.getLayer();
|
||||||
int i = location.getI();
|
// int i = location.getI();
|
||||||
int j = location.getJ();
|
// int j = location.getJ();
|
||||||
String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
|
// String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
|
||||||
|
//
|
||||||
File file = new File(fileName);
|
// File file = new File(fileName);
|
||||||
file.createNewFile();
|
// file.createNewFile();
|
||||||
FileOutputStream fos = new FileOutputStream(file);
|
// FileOutputStream fos = new FileOutputStream(file);
|
||||||
fos.write(proof.toByteArray());
|
// fos.write(proof.toByteArray());
|
||||||
fos.close();
|
// fos.close();
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create new file contains single encrypted message
|
* create new file contains single encrypted message
|
||||||
|
|
|
@ -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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@ import java.math.BigInteger;
|
||||||
*
|
*
|
||||||
* both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it
|
* both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it
|
||||||
*/
|
*/
|
||||||
public class ECElGamalMixParams {
|
public class ECElGamalMixStatementGenerator {
|
||||||
|
|
||||||
final ECElGamalEncryption encryptor;
|
final ECElGamalEncryption encryptor;
|
||||||
final ECGroup group;
|
final ECGroup group;
|
||||||
|
@ -31,7 +31,7 @@ public class ECElGamalMixParams {
|
||||||
* @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
|
* @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)
|
* 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.encryptor = encryptor;
|
||||||
this.group = encryptor.getGroup();
|
this.group = encryptor.getGroup();
|
||||||
this.g = group.getGenerator();
|
this.g = group.getGenerator();
|
||||||
|
@ -40,11 +40,6 @@ public class ECElGamalMixParams {
|
||||||
this.hEncoded = encryptor.encodeElement(h);
|
this.hEncoded = encryptor.encodeElement(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TrueCouple {
|
|
||||||
left, right, unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* can be used by anyone, e.g meerkat.mixer.verifier
|
* 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.
|
* 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 {
|
public class Mix2Statement {
|
||||||
|
@ -180,9 +175,9 @@ public class ECElGamalMixParams {
|
||||||
|
|
||||||
|
|
||||||
DlogStatement(ECPoint a, ECPoint b) {
|
DlogStatement(ECPoint a, ECPoint b) {
|
||||||
this.g = ECElGamalMixParams.this.g;
|
this.g = ECElGamalMixStatementGenerator.this.g;
|
||||||
this.a = a;
|
this.a = a;
|
||||||
this.h = ECElGamalMixParams.this.h;
|
this.h = ECElGamalMixStatementGenerator.this.h;
|
||||||
this.b = b;
|
this.b = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package meerkat.mixer.proofs;
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||||
import meerkat.crypto.concrete.Util;
|
|
||||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||||
import meerkat.protobuf.Crypto;
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.Mixing;
|
import meerkat.protobuf.Mixing;
|
||||||
|
@ -26,8 +25,7 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
||||||
private final ECElGamalEncryption encryptor;
|
private final ECElGamalEncryption encryptor;
|
||||||
private final ECPoint g,h;
|
private final ECPoint g,h;
|
||||||
private final BigInteger groupOrderUpperBound;
|
private final BigInteger groupOrderUpperBound;
|
||||||
private final ECElGamalMixParams mixParams;
|
private final ECElGamalMixStatementGenerator mixParams;
|
||||||
final ECElGamalMixProtocols mixProtocols;
|
|
||||||
final SigmaFiatShamir<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> mix2NIZK;
|
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.group = this.encryptor.getGroup();
|
||||||
this.g = group.getGenerator();
|
this.g = group.getGenerator();
|
||||||
this.h = this.encryptor.getElGamalPK().getPK();
|
this.h = this.encryptor.getElGamalPK().getPK();
|
||||||
this.mixParams = new ECElGamalMixParams(encryptor);
|
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
|
||||||
this.groupOrderUpperBound = group.orderUpperBound();
|
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);
|
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 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 d - if switched then d = rerandomize(a,r1) else d = rerandomize(b,r2)
|
||||||
* @param switched - trueClauseIndex
|
* @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 layer - row of a,b in encryption table
|
||||||
* @param r1
|
* @param r1
|
||||||
* @param r2
|
* @param r2
|
||||||
|
@ -67,186 +62,25 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
||||||
Crypto.RerandomizableEncryptedMessage b,
|
Crypto.RerandomizableEncryptedMessage b,
|
||||||
Crypto.RerandomizableEncryptedMessage c,
|
Crypto.RerandomizableEncryptedMessage c,
|
||||||
Crypto.RerandomizableEncryptedMessage d,
|
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 r1,
|
||||||
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
||||||
|
|
||||||
|
|
||||||
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(a,b,c,d);
|
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(a, b, c, d);
|
||||||
ECElGamalMixParams.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
|
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()
|
Mixing.Mix2Proof.Location location = Mixing.Mix2Proof.Location.newBuilder()
|
||||||
.setI(i)
|
.setLayer(layer)
|
||||||
.setJ(j)
|
.setSwitchIdx(switchIdx)
|
||||||
.setLayer(layer).build();
|
.setOut0(out0Idx)
|
||||||
|
.setOut1(out1Idx)
|
||||||
|
.build();
|
||||||
return mix2NIZK.generateNizk(prover).toBuilder().setLocation(location).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();
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,23 +12,11 @@ public interface SigmaProtocol {
|
||||||
public interface Prover <FirstMsgType, FinalMessageType> {
|
public interface Prover <FirstMsgType, FinalMessageType> {
|
||||||
public FirstMsgType getFirstMessage();
|
public FirstMsgType getFirstMessage();
|
||||||
public FinalMessageType getFinalMessage(BigInteger challenge);
|
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 interface Simulator <FirstMsgType, FinalMessageType> {
|
||||||
public FirstMsgType getFirstMessage(BigInteger challenge);
|
public FirstMsgType getFirstMessage(BigInteger challenge);
|
||||||
public FinalMessageType getFinalMessage();
|
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> {
|
public interface Verifier <FirstMsgType, FinalMessageType> {
|
||||||
|
|
|
@ -29,10 +29,6 @@ public class SigmaProtocolAnd2 {
|
||||||
public FinalMessageOut getFinalMessage(BigInteger challenge) {
|
public FinalMessageOut getFinalMessage(BigInteger challenge) {
|
||||||
return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(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,
|
static public class Verifier<FirstMessageOut, FirstMessageIn,
|
||||||
|
@ -80,8 +76,6 @@ public class SigmaProtocolAnd2 {
|
||||||
return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() { simulators[0].reset(); simulators[1].reset(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,6 @@ public class SigmaProtocolOr2 {
|
||||||
return finalMessageConcatenator.concatenate(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge));
|
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>
|
static public class Verifier <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||||
|
@ -142,9 +139,6 @@ public class SigmaProtocolOr2 {
|
||||||
public FinalMessageOut getFinalMessage() {
|
public FinalMessageOut getFinalMessage() {
|
||||||
return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() { simulators[0].reset(); simulators[1].reset(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import meerkat.protobuf.Mixing;
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
import org.factcenter.qilin.primitives.RandomOracle;
|
import org.factcenter.qilin.primitives.RandomOracle;
|
||||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||||
import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* implements Mix2ZeroKnowledgeVerifier
|
* implements Mix2ZeroKnowledgeVerifier
|
||||||
|
@ -16,11 +15,11 @@ import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
|
||||||
public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
||||||
|
|
||||||
|
|
||||||
|
private final ECElGamalEncryption encryptor;
|
||||||
private final ECGroup group;
|
private final ECGroup group;
|
||||||
private final RandomOracle randomOracle;
|
private final RandomOracle randomOracle;
|
||||||
private final ECPoint g,h;
|
private final ECPoint g,h;
|
||||||
private final ECElGamalMixParams mixParams;
|
private final ECElGamalMixStatementGenerator mixParams;
|
||||||
final ECElGamalMixProtocols mixProtocols;
|
|
||||||
final SigmaFiatShamir mix2NIZK;
|
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
|
* @param randomOracle should be as the random oracle used by meerkat.mixer.proofs
|
||||||
*/
|
*/
|
||||||
public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) {
|
public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) {
|
||||||
|
this.encryptor = encryptor;
|
||||||
this.group = encryptor.getGroup();
|
this.group = encryptor.getGroup();
|
||||||
this.g = group.getGenerator();
|
this.g = group.getGenerator();
|
||||||
this.h = encryptor.getElGamalPK().getPK();
|
this.h = encryptor.getElGamalPK().getPK();
|
||||||
this.randomOracle = randomOracle;
|
this.randomOracle = randomOracle;
|
||||||
this.mixParams = new ECElGamalMixParams(encryptor);
|
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
|
||||||
this.mixProtocols = new ECElGamalMixProtocols(mixParams, null); // We don't need randomness for the verifier
|
|
||||||
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
|
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
|
||||||
// this.parser = new ZeroKnowledgeOrProofParser(group);
|
// this.parser = new ZeroKnowledgeOrProofParser(group);
|
||||||
}
|
}
|
||||||
|
@ -60,8 +59,8 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
||||||
Crypto.RerandomizableEncryptedMessage out2,
|
Crypto.RerandomizableEncryptedMessage out2,
|
||||||
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException {
|
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException {
|
||||||
|
|
||||||
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||||
Mix2Verifier verifier = mixProtocols.new Mix2Verifier(statement);
|
Mix2.Verifier verifier = new Mix2.Verifier(encryptor, statement);
|
||||||
|
|
||||||
return mix2NIZK.verifyNizk(proof, verifier);
|
return mix2NIZK.verifyNizk(proof, verifier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,17 @@ public final class VerifyTable {
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
* @param verifier
|
* @param verifier
|
||||||
* @param n
|
|
||||||
* @param mixerOutput
|
* @param mixerOutput
|
||||||
* @return true iff the meerkat.mixer.mixing output is valid
|
* @return true iff the meerkat.mixer.mixing output is valid
|
||||||
* @throws InvalidProtocolBufferException
|
* @throws InvalidProtocolBufferException
|
||||||
*/
|
*/
|
||||||
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput)
|
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier, MixerOutput mixerOutput)
|
||||||
throws InvalidProtocolBufferException {
|
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
|
//initialize locationChecksum table
|
||||||
// use for check BeneshNet validity
|
// use for check BeneshNet validity
|
||||||
boolean[][] locationChecksum = new boolean[layers][n];
|
boolean[][] locationChecksum = new boolean[layers][n];
|
||||||
|
@ -44,36 +41,32 @@ public final class VerifyTable {
|
||||||
for (int j = 0; j < Mix2Proofs[i].length ; j ++){
|
for (int j = 0; j < Mix2Proofs[i].length ; j ++){
|
||||||
Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
|
Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
|
||||||
Mixing.Mix2Proof.Location location = zkp.getLocation();
|
Mixing.Mix2Proof.Location location = zkp.getLocation();
|
||||||
index1 = location.getI();
|
out0 = location.getOut0();
|
||||||
index2 = location.getJ();
|
out1 = location.getOut1();
|
||||||
layer = location.getLayer();
|
layer = location.getLayer();
|
||||||
|
switchIdx = location.getSwitchIdx();
|
||||||
|
|
||||||
// check location validity
|
// check location validity
|
||||||
if (layer > layers >> 1) {
|
// TODO: add check
|
||||||
if (index2 - index1 != n >> (layers - layer))
|
// if (layer > layers >> 1) {
|
||||||
return false;
|
// if (out1 - out0 != n >> (layers - layer))
|
||||||
}
|
// return false;
|
||||||
else{
|
// }
|
||||||
if (index2 - index1 != n >> (layer + 1))
|
// else{
|
||||||
return false;
|
// if (out1 - out0 != n >> (layer + 1))
|
||||||
}
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
// mark location in table
|
// mark location in table
|
||||||
locationChecksum[layer][index1] = true;
|
locationChecksum[layer][2 * switchIdx] = true;
|
||||||
locationChecksum[layer][index2] = true;
|
locationChecksum[layer][2 * switchIdx + 1] = true;
|
||||||
|
|
||||||
// verify proof
|
// verify proof
|
||||||
if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx],
|
||||||
rerandomizableEncryptedMessages[layer][index2],
|
rerandomizableEncryptedMessages[layer][2 * switchIdx + 1],
|
||||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
rerandomizableEncryptedMessages[layer + 1][out0],
|
||||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
rerandomizableEncryptedMessages[layer + 1][out1],
|
||||||
zkp)) {
|
zkp)) {
|
||||||
|
|
||||||
verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
|
||||||
rerandomizableEncryptedMessages[layer][index2],
|
|
||||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
|
||||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
|
||||||
zkp);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@ option java_package = "meerkat.protobuf";
|
||||||
import 'meerkat/crypto.proto';
|
import 'meerkat/crypto.proto';
|
||||||
import 'meerkat/concrete_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 {
|
message Plaintext {
|
||||||
bytes data = 1;
|
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
|
BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Location of the
|
||||||
message Location {
|
message Location {
|
||||||
int32 i = 1;
|
int32 layer = 1; // layer in which the switch is placed
|
||||||
int32 j = 2;
|
int32 switchIdx = 2; // idx of the switch
|
||||||
int32 layer = 3;
|
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;
|
FirstMessage firstMessage = 1;
|
||||||
FinalMessage finalMessage = 2;
|
FinalMessage finalMessage = 2;
|
||||||
Location location = 5;
|
Location location = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,100 +1,100 @@
|
||||||
package meerkat.mixer;
|
//package meerkat.mixer;
|
||||||
|
//
|
||||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
//import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||||
import meerkat.mixer.mixing.Mixer;
|
//import meerkat.mixer.mixing.Mixer;
|
||||||
import meerkat.mixer.mixing.MixerOutput;
|
//import meerkat.mixer.mixing.MixerOutput;
|
||||||
import meerkat.mixer.proofs.Prover;
|
//import meerkat.mixer.proofs.Prover;
|
||||||
import meerkat.mixer.proofs.Verifier;
|
//import meerkat.mixer.proofs.Verifier;
|
||||||
import meerkat.mixer.proofs.VerifyTable;
|
//import meerkat.mixer.proofs.VerifyTable;
|
||||||
import meerkat.protobuf.Crypto;
|
//import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.Voting;
|
//import meerkat.protobuf.Voting;
|
||||||
import org.factcenter.qilin.primitives.RandomOracle;
|
//import org.factcenter.qilin.primitives.RandomOracle;
|
||||||
import org.factcenter.qilin.primitives.concrete.DigestOracle;
|
//import org.factcenter.qilin.primitives.concrete.DigestOracle;
|
||||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
//import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
//import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||||
import org.junit.Before;
|
//import org.junit.Before;
|
||||||
|
//
|
||||||
import java.io.IOException;
|
//import java.io.IOException;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
//import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.ArrayList;
|
//import java.util.ArrayList;
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Random;
|
//import java.util.Random;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* Created by Tzlil on 1/19/2016.
|
// * Created by Tzlil on 1/19/2016.
|
||||||
*/
|
// */
|
||||||
public class CreateTestVector {
|
//public class CreateTestVector {
|
||||||
|
//
|
||||||
|
//
|
||||||
ECElGamalEncryption encryptor;
|
// ECElGamalEncryption encryptor;
|
||||||
ECGroup group;
|
// ECGroup group;
|
||||||
Random random,randomMixer,randomProver;
|
// Random random,randomMixer,randomProver;
|
||||||
RandomOracle randomOracle;
|
// RandomOracle randomOracle;
|
||||||
Mix2ZeroKnowledgeVerifier verifier;
|
// Mix2ZeroKnowledgeVerifier verifier;
|
||||||
Mix2ZeroKnowledgeProver prover;
|
// Mix2ZeroKnowledgeProver prover;
|
||||||
meerkat.crypto.mixnet.Mixer mixer;
|
// meerkat.crypto.mixnet.Mixer mixer;
|
||||||
private int layers;
|
// private int layers;
|
||||||
private int n;
|
// private int n;
|
||||||
|
//
|
||||||
|
//
|
||||||
@Before
|
// @Before
|
||||||
public void setup() throws InvalidKeySpecException {
|
// public void setup() throws InvalidKeySpecException {
|
||||||
// initialization
|
// // initialization
|
||||||
random = new Random();
|
// random = new Random();
|
||||||
group = new ECGroup("secp256k1");
|
// group = new ECGroup("secp256k1");
|
||||||
encryptor = new ECElGamalEncryption();
|
// encryptor = new ECElGamalEncryption();
|
||||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
// encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||||
randomMixer = new Random();
|
// randomMixer = new Random();
|
||||||
randomProver = new Random();
|
// randomProver = new Random();
|
||||||
randomOracle = new DigestOracle();
|
// randomOracle = new DigestOracle();
|
||||||
verifier = new Verifier(encryptor,randomOracle);
|
// verifier = new Verifier(encryptor,randomOracle);
|
||||||
prover = new Prover(randomProver,encryptor,randomOracle);
|
// prover = new Prover(randomProver,encryptor,randomOracle);
|
||||||
mixer = new Mixer(prover,encryptor);
|
// mixer = new Mixer(prover,encryptor);
|
||||||
|
//
|
||||||
// generate n
|
// // generate n
|
||||||
int logN = 10; // + random.nextInt(8)
|
// int logN = 10; // + random.nextInt(8)
|
||||||
layers = 2*logN - 1;
|
// layers = 2*logN - 1;
|
||||||
n = 1 << logN;
|
// n = 1 << logN;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
|
// public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
|
||||||
List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
|
// List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
|
||||||
Voting.PlaintextBallot msg;
|
// Voting.PlaintextBallot msg;
|
||||||
for (int i = 0; i < n ; i++){
|
// for (int i = 0; i < n ; i++){
|
||||||
msg = Utils.genRandomBallot(2,3,16);
|
// msg = Utils.genRandomBallot(2,3,16);
|
||||||
result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
|
// result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
|
||||||
}
|
// }
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
//@SimpleRerandomizeTest
|
// //@SimpleRerandomizeTest
|
||||||
public void createValidTest() throws IOException {
|
// public void createValidTest() throws IOException {
|
||||||
|
//
|
||||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||||
System.out.println("start mixing");
|
// System.out.println("start mixing");
|
||||||
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
|
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
|
||||||
System.out.println("mixing ended, start verification");
|
// System.out.println("mixing ended, start verification");
|
||||||
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
// assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||||
System.out.println("verification ended, start printing");
|
// System.out.println("verification ended, start printing");
|
||||||
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
|
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
|
||||||
System.out.println("all done");
|
// System.out.println("all done");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
//@SimpleRerandomizeTest
|
// //@SimpleRerandomizeTest
|
||||||
public void createInvalidTest() throws IOException {
|
// public void createInvalidTest() throws IOException {
|
||||||
|
//
|
||||||
//Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
|
// //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
|
||||||
//Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
|
// //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
|
||||||
//mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
|
// //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
|
||||||
|
//
|
||||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||||
System.out.println("start mixing");
|
// System.out.println("start mixing");
|
||||||
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
|
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
|
||||||
System.out.println("mixing ended, start negative verification");
|
// System.out.println("mixing ended, start negative verification");
|
||||||
assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
|
// assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||||
System.out.println("verification ended, start printing");
|
// System.out.println("verification ended, start printing");
|
||||||
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
|
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
|
||||||
System.out.println("all done");
|
// System.out.println("all done");
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class Mix2ProofTest extends ECParamTestBase {
|
||||||
group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));
|
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));
|
assertTrue (verifier.verify(e1,e2,e1New,e2New, proof));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -45,7 +45,7 @@ public class MixingTest extends ECParamTestBase {
|
||||||
mixer = new Mixer(prover, enc);
|
mixer = new Mixer(prover, enc);
|
||||||
|
|
||||||
// generate n
|
// generate n
|
||||||
int logN = 9; // + random.nextInt(8)
|
int logN = 5; // + random.nextInt(8)
|
||||||
layers = 2*logN - 1;
|
layers = 2*logN - 1;
|
||||||
n = 1 << logN;
|
n = 1 << logN;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public class MixingTest extends ECParamTestBase {
|
||||||
System.out.println("start verification");
|
System.out.println("start verification");
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
assert (VerifyTable.verifyTable(verifier,mixerOutput));
|
||||||
|
|
||||||
finishTime = System.currentTimeMillis();
|
finishTime = System.currentTimeMillis();
|
||||||
System.out.println(" that took: "+(finishTime-startTime)+ " ms");
|
System.out.println(" that took: "+(finishTime-startTime)+ " ms");
|
||||||
|
|
|
@ -11,8 +11,8 @@ import java.math.BigInteger;
|
||||||
public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
|
public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
|
||||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||||
|
|
||||||
ECElGamalMixParams.DlogStatement s1, s2;
|
ECElGamalMixStatementGenerator.DlogStatement s1, s2;
|
||||||
ECElGamalMixParams.DlogStatementWitness w1, w2;
|
ECElGamalMixStatementGenerator.DlogStatementWitness w1, w2;
|
||||||
|
|
||||||
public DlogAndStatementSigmaTest() {
|
public DlogAndStatementSigmaTest() {
|
||||||
this.dlogtest = new DlogStatementSchnorrSigmaTest();
|
this.dlogtest = new DlogStatementSchnorrSigmaTest();
|
||||||
|
@ -20,10 +20,10 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void generateRandomTrueStatement() {
|
void generateRandomTrueStatement() {
|
||||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||||
s1 = s1w1.a; w1 = s1w1.b;
|
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;
|
s2 = s2w2.a; w2 = s2w2.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,19 +36,19 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
|
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
|
||||||
return new SigmaProtocolAnd2.Prover<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
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
|
@Override
|
||||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewVerifier() {
|
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewVerifier() {
|
||||||
return new SigmaProtocolAnd2.Verifier<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
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
|
@Override
|
||||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewSimulator() {
|
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewSimulator() {
|
||||||
return new SigmaProtocolAnd2.Simulator<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
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
|
@Override
|
||||||
|
|
|
@ -11,8 +11,8 @@ import java.math.BigInteger;
|
||||||
public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> {
|
public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> {
|
||||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||||
|
|
||||||
final ECElGamalMixParams.AndStatement[] statements = new ECElGamalMixParams.AndStatement[2];
|
final ECElGamalMixStatementGenerator.AndStatement[] statements = new ECElGamalMixStatementGenerator.AndStatement[2];
|
||||||
ECElGamalMixParams.AndStatementWitness w;
|
ECElGamalMixStatementGenerator.AndStatementWitness w;
|
||||||
int trueStatementIndex;
|
int trueStatementIndex;
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,53 +23,57 @@ public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof
|
||||||
@Override
|
@Override
|
||||||
void generateRandomTrueStatement() {
|
void generateRandomTrueStatement() {
|
||||||
trueStatementIndex = rand.nextInt(2);
|
trueStatementIndex = rand.nextInt(2);
|
||||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||||
ECElGamalMixParams.AndStatement trueStatement = dlogtest.params.new AndStatement(s1w1.a, s2w2.a);
|
ECElGamalMixStatementGenerator.AndStatement trueStatement = dlogtest.statementGenerator.new AndStatement(s1w1.a, s2w2.a);
|
||||||
w = dlogtest.params.new AndStatementWitness(s1w1.b, s2w2.b);
|
w = dlogtest.statementGenerator.new AndStatementWitness(s1w1.b, s2w2.b);
|
||||||
statements[trueStatementIndex] = trueStatement;
|
statements[trueStatementIndex] = trueStatement;
|
||||||
|
|
||||||
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||||
ECElGamalMixParams.DlogStatement f2 = 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;
|
statements[1 - trueStatementIndex] = falseStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void generateRandomFalseStatement() {
|
void generateRandomFalseStatement() {
|
||||||
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||||
ECElGamalMixParams.DlogStatement f2 = 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();
|
f1 = dlogtest.returnRandomFalseStatement();
|
||||||
f2 = dlogtest.returnRandomFalseStatement();
|
f2 = dlogtest.returnRandomFalseStatement();
|
||||||
statements[1] = dlogtest.params.new AndStatement(f1, f2);
|
statements[1] = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewProver() {
|
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.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 = dlogtest.prots.new AndStatementSimulator(statements[1 - trueStatementIndex]);
|
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,
|
return new SigmaProtocolOr2.Prover<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||||
dlogtest.prots.challengeGenerator, andProver, andSimulator, trueStatementIndex);
|
gen, andProver, andSimulator, trueStatementIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewVerifier() {
|
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,
|
return new SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage,
|
||||||
Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
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
|
@Override
|
||||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewSimulator() {
|
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,
|
return new SigmaProtocolOr2.Simulator<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||||
dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementSimulator(statements[0]),
|
gen, new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[0]),
|
||||||
dlogtest.prots.new AndStatementSimulator(statements[1]));
|
new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package meerkat.mixer.proofs;
|
package meerkat.mixer.proofs;
|
||||||
|
|
||||||
|
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||||
import meerkat.mixer.ECParamTestBase;
|
import meerkat.mixer.ECParamTestBase;
|
||||||
import meerkat.protobuf.Mixing;
|
import meerkat.protobuf.Mixing;
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||||
import org.factcenter.qilin.util.Pair;
|
import org.factcenter.qilin.util.Pair;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
@ -13,42 +15,44 @@ import java.math.BigInteger;
|
||||||
public class DlogStatementSchnorrSigmaTest extends
|
public class DlogStatementSchnorrSigmaTest extends
|
||||||
SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
||||||
|
|
||||||
ECParamTestBase ecParams = new ECParamTestBase();
|
ECParamTestBase ecParams;
|
||||||
ECElGamalMixParams params;
|
ECElGamalMixStatementGenerator statementGenerator;
|
||||||
ECElGamalMixProtocols prots;
|
ECElGamalEncryption encryptor;
|
||||||
|
ECGroup group;
|
||||||
|
|
||||||
ECElGamalMixParams.DlogStatement statement;
|
ECElGamalMixStatementGenerator.DlogStatement statement;
|
||||||
ECElGamalMixParams.DlogStatementWitness witness;
|
ECElGamalMixStatementGenerator.DlogStatementWitness witness;
|
||||||
ECElGamalMixProtocols.DlogStatementSchnorrProver prover;
|
SchnorrDlogEquivalence.Prover prover;
|
||||||
ECElGamalMixProtocols.DlogStatementSchnorrVerifier verifier;
|
SchnorrDlogEquivalence.Verifier verifier;
|
||||||
ECElGamalMixProtocols.DlogStatementSchnorrSimulator simulator;
|
SchnorrDlogEquivalence.Simulator simulator;
|
||||||
|
|
||||||
public DlogStatementSchnorrSigmaTest() {
|
public DlogStatementSchnorrSigmaTest() {
|
||||||
|
ecParams = new ECParamTestBase();
|
||||||
this.params = new ECElGamalMixParams(ecParams.enc);
|
encryptor = ecParams.enc;
|
||||||
this.prots = new ECElGamalMixProtocols(params, rand); // We don't need randomness for the verifier
|
group = encryptor.getGroup();
|
||||||
|
this.statementGenerator = new ECElGamalMixStatementGenerator(ecParams.enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> returnRandomTrueStatement() {
|
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> returnRandomTrueStatement() {
|
||||||
BigInteger x = prots.encryptor.generateRandomExponent(rand);
|
BigInteger x = encryptor.generateRandomExponent(rand);
|
||||||
ECPoint a = prots.group.multiply(prots.g, x);
|
ECPoint a = group.multiply(statementGenerator.g, x);
|
||||||
ECPoint b = prots.group.multiply(prots.h, x);
|
ECPoint b = group.multiply(statementGenerator.h, x);
|
||||||
ECElGamalMixParams.DlogStatement statement = params.new DlogStatement(a, b);
|
ECElGamalMixStatementGenerator.DlogStatement statement = statementGenerator.new DlogStatement(a, b);
|
||||||
ECElGamalMixParams.DlogStatementWitness witness = params.new DlogStatementWitness(x);
|
ECElGamalMixStatementGenerator.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x);
|
||||||
|
|
||||||
return new Pair<>(statement, witness);
|
return new Pair<>(statement, witness);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECElGamalMixParams.DlogStatement returnRandomFalseStatement() {
|
ECElGamalMixStatementGenerator.DlogStatement returnRandomFalseStatement() {
|
||||||
ECPoint a = prots.group.sample(rand);
|
ECPoint a = group.sample(rand);
|
||||||
ECPoint b = prots.group.sample(rand);
|
ECPoint b = group.sample(rand);
|
||||||
|
|
||||||
return params.new DlogStatement(a, b);
|
return statementGenerator.new DlogStatement(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateRandomTrueStatement() {
|
void generateRandomTrueStatement() {
|
||||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> sw = returnRandomTrueStatement();
|
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> sw = returnRandomTrueStatement();
|
||||||
this.statement = sw.a;
|
this.statement = sw.a;
|
||||||
this.witness = sw.b;
|
this.witness = sw.b;
|
||||||
}
|
}
|
||||||
|
@ -60,24 +64,24 @@ public class DlogStatementSchnorrSigmaTest extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
|
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;
|
return prover;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
|
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;
|
return verifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewSimulator() {
|
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;
|
return simulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BigInteger getChallengeModulus() {
|
protected BigInteger getChallengeModulus() {
|
||||||
return prots.group.orderUpperBound();
|
return group.orderUpperBound();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,11 +34,6 @@ public class DummySigmaProof {
|
||||||
public BigInteger getFinalMessage(BigInteger challenge) {
|
public BigInteger getFinalMessage(BigInteger challenge) {
|
||||||
return challenge.add(r.multiply(x.add(y)));
|
return challenge.add(r.multiply(x.add(y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static class Verifier implements SigmaProtocol.Verifier<Crypto.BigInteger,BigInteger> {
|
public static class Verifier implements SigmaProtocol.Verifier<Crypto.BigInteger,BigInteger> {
|
||||||
|
|
||||||
|
@ -81,11 +76,6 @@ public class DummySigmaProof {
|
||||||
public BigInteger getFinalMessage() {
|
public BigInteger getFinalMessage() {
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class ZeroKnowledgeProof {
|
||||||
|
|
||||||
for (int i = 0; i < n*2 ; i +=2){
|
for (int i = 0; i < n*2 ; i +=2){
|
||||||
prover.prove(encryptedMessage[i],encryptedMessage[i+1],reencryptedMessage[i],reencryptedMessage[i+1],
|
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();
|
long finishTime = System.currentTimeMillis();
|
||||||
|
|
Loading…
Reference in New Issue