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 Mixing.Mix2Proof[][] getProofs();
|
||||
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
|
||||
*/
|
||||
public class BatchConverter {
|
||||
|
||||
private final int n,layers;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n
|
||||
* @param layers
|
||||
*/
|
||||
public BatchConverter(int n,int layers){
|
||||
this.n = n;
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert integer to byte string
|
||||
* @param a
|
||||
* @return a as byte string
|
||||
*/
|
||||
private ByteString Integer2ByteString(int a){
|
||||
return ByteString.copyFrom(BigInteger.valueOf(a).toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert byte string to integer
|
||||
* @param bs
|
||||
* @return bs as int
|
||||
*/
|
||||
private int ByteString2Integer(ByteString bs) {
|
||||
return Integer.valueOf(bs.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convert meerkat.mixer.mixing output to batch data
|
||||
* @param mixerOutput
|
||||
|
@ -55,8 +24,13 @@ public class BatchConverter {
|
|||
|
||||
List<BulletinBoardAPI.BatchChunk> result = new ArrayList<BulletinBoardAPI.BatchChunk>();
|
||||
|
||||
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.newBuilder()
|
||||
.setLogN(mixerOutput.getLogN())
|
||||
.setLayers(mixerOutput.getNumLayers())
|
||||
.build();
|
||||
|
||||
result.add(BulletinBoardAPI.BatchChunk.newBuilder()
|
||||
.setData(Integer2ByteString(n))
|
||||
.setData(header.toByteString())
|
||||
.build());
|
||||
|
||||
for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) {
|
||||
|
@ -85,10 +59,11 @@ public class BatchConverter {
|
|||
public MixerOutput BatchChunkList2MixerOutput
|
||||
(List<BulletinBoardAPI.BatchChunk> batchChunkList) throws Exception {
|
||||
|
||||
if (n != ByteString2Integer(batchChunkList.remove(0).getData())){
|
||||
throw new Exception();
|
||||
}
|
||||
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseFrom(batchChunkList.remove(0).getData());
|
||||
|
||||
int logN = header.getLogN();
|
||||
int n = 1 << logN;
|
||||
int layers = header.getLayers();
|
||||
int nDiv2 = n >>1;
|
||||
Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2];
|
||||
for (int layer = 0; layer < layers; layer++)
|
||||
|
@ -110,7 +85,7 @@ public class BatchConverter {
|
|||
}
|
||||
}
|
||||
|
||||
return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions);
|
||||
return new meerkat.mixer.mixing.MixerOutput(logN, proofs,encryptions);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,19 +21,14 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
|||
private Throwable t;
|
||||
private CompleteBatch msg;
|
||||
|
||||
private final int n, layers;
|
||||
private final Mix2ZeroKnowledgeVerifier verifier;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n
|
||||
* @param layers
|
||||
* @param verifier
|
||||
*/
|
||||
public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) {
|
||||
public BatchHandler(Mix2ZeroKnowledgeVerifier verifier) {
|
||||
this.mixerOutput = null;
|
||||
this.n = n;
|
||||
this.layers = layers;
|
||||
this.msgReceived = false;
|
||||
this.t = null;
|
||||
this.verifier = verifier;
|
||||
|
@ -70,7 +65,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
|||
* @throws Exception
|
||||
*/
|
||||
private void convertMessage() throws Exception {
|
||||
BatchConverter batchConverter = new BatchConverter(n,layers);
|
||||
BatchConverter batchConverter = new BatchConverter();
|
||||
this.mixerOutput = batchConverter.BatchChunkList2MixerOutput(msg.getBatchChunkList());
|
||||
}
|
||||
|
||||
|
@ -83,7 +78,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
|||
if (mixerOutput == null) {
|
||||
convertMessage();
|
||||
}
|
||||
return VerifyTable.verifyTable(verifier, n, mixerOutput);
|
||||
return VerifyTable.verifyTable(verifier, mixerOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,7 +93,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
|||
if(!verifyTable()){
|
||||
throw new Exception("in valid table");
|
||||
}
|
||||
return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1
|
||||
return Arrays.asList(mixerOutput.getEncryptedMessages()[mixerOutput.getNumLayers()]);//there are layers + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import meerkat.crypto.mixnet.Mixer;
|
|||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.protobuf.BulletinBoardAPI;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.mixer.mixing.MixNetwork;
|
||||
import meerkat.mixer.necessary.AsyncBulletinBoardClient;
|
||||
|
||||
|
||||
|
@ -26,7 +25,6 @@ public class MainMixing {
|
|||
|
||||
private final Mixer mixer;
|
||||
private final Mix2ZeroKnowledgeVerifier verifier;
|
||||
private final int n, layers;
|
||||
private final AsyncBulletinBoardClient asyncBulletinBoardClient;
|
||||
private final byte[] id;
|
||||
|
||||
|
@ -35,16 +33,13 @@ public class MainMixing {
|
|||
* constructor
|
||||
* @param mixer
|
||||
* @param verifier
|
||||
* @param n
|
||||
* @param asyncBulletinBoardClient
|
||||
* @param id
|
||||
*/
|
||||
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier, int n
|
||||
, AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
|
||||
public MainMixing(Mixer mixer, Mix2ZeroKnowledgeVerifier verifier,
|
||||
AsyncBulletinBoardClient asyncBulletinBoardClient, byte[] id) {
|
||||
this.mixer = mixer;
|
||||
this.verifier = verifier;
|
||||
this.n = n;
|
||||
this.layers = MixNetwork.numberOfLayers(n);
|
||||
this.asyncBulletinBoardClient = asyncBulletinBoardClient;
|
||||
this.id = id;
|
||||
}
|
||||
|
@ -64,7 +59,7 @@ public class MainMixing {
|
|||
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
|
||||
BatchHandler currentBatchHandler;
|
||||
for (Integer prevBatchId : prevBatchIds) {
|
||||
currentBatchHandler = new BatchHandler(n, layers,verifier);
|
||||
currentBatchHandler = new BatchHandler(verifier);
|
||||
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
|
||||
batchHandlers.add(currentBatchHandler);
|
||||
}
|
||||
|
@ -99,7 +94,7 @@ public class MainMixing {
|
|||
private void updateBB(MixerOutput mixerOutput
|
||||
, int batchId, AsyncBulletinBoardClient.ClientCallback<?> callback) {
|
||||
|
||||
BatchConverter batchConverter = new BatchConverter(n,layers);
|
||||
BatchConverter batchConverter = new BatchConverter();
|
||||
List<BulletinBoardAPI.BatchChunk> batchChunkList = batchConverter.MixerOutput2BatchChunk(mixerOutput);
|
||||
asyncBulletinBoardClient.postBatch(id, batchId, batchChunkList, callback);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* @param n number of votes
|
||||
* @param logN log number of votes
|
||||
* @param random
|
||||
* @return new random mix network
|
||||
*/
|
||||
private MixNetwork generateMixNetwork(int n,Random random){
|
||||
return new MixNetwork(new RandomPermutation(n,random));
|
||||
private PermutationNetwork generateMixNetwork(int logN, Random random){
|
||||
BenesNetwork net = new BenesNetwork(logN);
|
||||
RandomPermutation perm = new RandomPermutation(1 << logN, random);
|
||||
net.setPermutation(perm.permutation);
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fills the encryption table with rerandomize encrypted votes.
|
||||
* @param layers
|
||||
* fills the encryption table with rerandomized encrypted votes.
|
||||
* @param mixNetwork switches table (boolean values)
|
||||
* @param encryptionTable an initialized encryption table s.t first layer == given encrypted votes
|
||||
* @param randomnesses an initialized randomness table of size layers * n, use for rerandomize operations
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
private void rerandomize(int layers,MixNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
|
||||
private void rerandomize(PermutationNetwork mixNetwork, RerandomizableEncryptedMessage[][] encryptionTable
|
||||
,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||
Switch[] switchesLayer;
|
||||
int index1,index2;
|
||||
RerandomizableEncryptedMessage e1,e2;
|
||||
RerandomizableEncryptedMessage a,b;
|
||||
EncryptionRandomness r1,r2;
|
||||
for (int layer = 0; layer < layers; layer++)
|
||||
{
|
||||
switchesLayer = mixNetwork.getSwitchesByLayer(layer);
|
||||
for (Switch sw : switchesLayer) {
|
||||
index1 = sw.i;
|
||||
index2 = sw.j;
|
||||
e1 = encryptionTable[layer][index1];
|
||||
e2 = encryptionTable[layer][index2];
|
||||
int layers = mixNetwork.getNumLayers();
|
||||
|
||||
r1 = randomnesses[layer][index1];
|
||||
r2 = randomnesses[layer][index2];
|
||||
if (!sw.value) {
|
||||
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e1, r1);
|
||||
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e2, r2);
|
||||
int numSwitches = mixNetwork.getNumInputs() >>> 1;
|
||||
|
||||
for (int layer = 0; layer < layers; layer++) {
|
||||
for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) {
|
||||
boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx);
|
||||
|
||||
int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx);
|
||||
int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
|
||||
|
||||
r1 = randomnesses[layer][2 * switchIdx];
|
||||
r2 = randomnesses[layer][2 * switchIdx + 1];
|
||||
|
||||
a = encryptionTable[layer][2 * switchIdx];
|
||||
b = encryptionTable[layer][2 * switchIdx + 1];
|
||||
|
||||
if (isCrossed) {
|
||||
encryptionTable[layer + 1][out0] = encryptor.rerandomize(b, r2);
|
||||
encryptionTable[layer + 1][out1] = encryptor.rerandomize(a, r1);
|
||||
} else {
|
||||
encryptionTable[layer + 1][index1] = encryptor.rerandomize(e2, r2);
|
||||
encryptionTable[layer + 1][index2] = encryptor.rerandomize(e1, r1);
|
||||
encryptionTable[layer + 1][out0] = encryptor.rerandomize(a, r1);
|
||||
encryptionTable[layer + 1][out1] = encryptor.rerandomize(b, r2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate zero knowledge proof for each rerandomize encrypted votes couple in encryptionTable
|
||||
* @param n number of votes
|
||||
* @param layers
|
||||
* @param mixNetwork switches table (boolean values) used for set encryption table
|
||||
* @param encryptionTable full encryption table
|
||||
* @param randomnesses randomness table of size layers * n, used for set encryption table
|
||||
* @return zero knowledge proofs table
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
private Mix2Proof[][] generateMix2ProofTable(int n, int layers, MixNetwork mixNetwork
|
||||
private Mix2Proof[][] generateMix2ProofTable(PermutationNetwork mixNetwork
|
||||
, RerandomizableEncryptedMessage[][] encryptionTable
|
||||
, EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||
int layers = mixNetwork.getNumLayers();
|
||||
int n = mixNetwork.getNumInputs();
|
||||
Switch[] switchesLayer;
|
||||
int index1,index2;
|
||||
int switchIndex = 0;
|
||||
int nDiv2 = n >> 1;
|
||||
Mix2Proof[][] proofsTable = new Mix2Proof[layers][nDiv2];
|
||||
int numSwitches = n >> 1;
|
||||
Mix2Proof[][] proofsTable = new Mix2Proof[layers][numSwitches];
|
||||
|
||||
RerandomizableEncryptedMessage e1,e2;
|
||||
RerandomizableEncryptedMessage a,b,c,d;
|
||||
EncryptionRandomness r1,r2;
|
||||
for (int layer = 0; layer < layers; layer++)
|
||||
{
|
||||
switchesLayer = mixNetwork.getSwitchesByLayer(layer);
|
||||
for (Switch sw : switchesLayer) {
|
||||
index1 = sw.i;
|
||||
index2 = sw.j;
|
||||
e1 = encryptionTable[layer][index1];
|
||||
e2 = encryptionTable[layer][index2];
|
||||
r1 = randomnesses[layer][index1];
|
||||
r2 = randomnesses[layer][index2];
|
||||
for (int layer = 0; layer < layers; layer++) {
|
||||
for (int switchIdx = 0; switchIdx < numSwitches; ++switchIdx) {
|
||||
boolean isCrossed = mixNetwork.isCrossed(layer, switchIdx);
|
||||
int out0 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx);
|
||||
int out1 = mixNetwork.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
|
||||
|
||||
a = encryptionTable[layer][2 * switchIdx];
|
||||
b = encryptionTable[layer][2 * switchIdx + 1];
|
||||
c = encryptionTable[layer + 1][out0];
|
||||
d = encryptionTable[layer + 1][out1];
|
||||
r1 = randomnesses[layer][2 * switchIdx];
|
||||
r2 = randomnesses[layer][2 * switchIdx + 1];
|
||||
|
||||
proofsTable[layer][switchIndex] =
|
||||
prover.prove(e1, e2, encryptionTable[layer + 1][index1],
|
||||
encryptionTable[layer + 1][index2],
|
||||
sw.value, sw.i, sw.j, sw.layer, r1, r2);
|
||||
|
||||
switchIndex = (switchIndex + 1) % nDiv2;
|
||||
prover.prove(a, b, c, d, isCrossed, layer, switchIdx, out0, out1, r1, r2);
|
||||
}
|
||||
}
|
||||
return proofsTable;
|
||||
|
@ -180,14 +187,18 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
|||
int n = ciphertexts.size();
|
||||
assert (n > 1 && isPowerOfTwo(n));
|
||||
|
||||
int layers = MixNetwork.numberOfLayers(n); // layers = 2logn -1
|
||||
int logN = Integer.numberOfTrailingZeros(Integer.highestOneBit(n)) + 1;
|
||||
|
||||
PermutationNetwork net = generateMixNetwork(logN,random);
|
||||
|
||||
int layers = net.getNumLayers();
|
||||
RerandomizableEncryptedMessage[][] encryptionTable = initializeEncryptionTable(n,layers,ciphertexts);
|
||||
EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random);
|
||||
MixNetwork mixNetwork = generateMixNetwork(n,random);
|
||||
rerandomize(layers,mixNetwork,encryptionTable,randomnesses);
|
||||
Mix2Proof[][] proofsTable = generateMix2ProofTable(n,layers,mixNetwork,encryptionTable,randomnesses);
|
||||
|
||||
return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable);
|
||||
rerandomize(net,encryptionTable,randomnesses);
|
||||
Mix2Proof[][] proofsTable = generateMix2ProofTable(net,encryptionTable,randomnesses);
|
||||
|
||||
return new meerkat.mixer.mixing.MixerOutput(logN, proofsTable, encryptionTable);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,26 +13,23 @@ import java.io.IOException;
|
|||
* implements meerkat.crypto.mixnet.MixerOutput interface
|
||||
* container for meerkat.mixer.mixing.mix result.
|
||||
*/
|
||||
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
||||
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput {
|
||||
private final Mixing.Mix2Proof[][] proofs;
|
||||
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
|
||||
private final int n;
|
||||
private final int layers;
|
||||
private final int logN;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n number of votes
|
||||
* @param layers
|
||||
* @param logN log (base 2) of the number of votes
|
||||
* @param encryptedMessages at level 0 , contains the original encrypted votes
|
||||
* at each other level contains the re encrypted votes
|
||||
* @param proofs in each cell (level,switch) contains the match zero knowledge proof
|
||||
*/
|
||||
public MixerOutput(int n,int layers,Mixing.Mix2Proof[][] proofs
|
||||
public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs
|
||||
, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
|
||||
this.proofs = proofs;
|
||||
this.encryptedMessages = encryptedMessages;
|
||||
this.n = n;
|
||||
this.layers = layers;
|
||||
this.logN = logN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,8 +45,13 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getN() {
|
||||
return n;
|
||||
public int getLogN() {
|
||||
return logN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumLayers() {
|
||||
return 2 * logN - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,33 +59,33 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
|||
* @param dir - directory
|
||||
* @throws IOException
|
||||
*/
|
||||
public void outToFolder(String dir) throws IOException {
|
||||
|
||||
(new File(dir)).mkdirs();
|
||||
//create files
|
||||
String proofsDir = dir + "/Proofs";
|
||||
String encDir = dir + "/EncryptedMessages";
|
||||
(new File(proofsDir)).mkdir();
|
||||
(new File(encDir)).mkdir();
|
||||
for (int layer = 0; layer < layers; layer++){
|
||||
(new File(proofsDir +"/layer" + layer )).mkdir();
|
||||
(new File(encDir +"/layer" + layer )).mkdir();
|
||||
}
|
||||
(new File(encDir +"/input")).mkdir();
|
||||
|
||||
|
||||
for (int layer = 0; layer < layers; layer++){
|
||||
for(int i = 0; i < proofs[layer].length; i ++){
|
||||
writeProofToFile(proofsDir,proofs[layer][i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int layer = 0; layer <= layers; layer++){
|
||||
for(int i = 0; i < encryptedMessages[layer].length; i ++){
|
||||
writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void outToFolder(String dir) throws IOException {
|
||||
//
|
||||
// (new File(dir)).mkdirs();
|
||||
// //create files
|
||||
// String proofsDir = dir + "/Proofs";
|
||||
// String encDir = dir + "/EncryptedMessages";
|
||||
// (new File(proofsDir)).mkdir();
|
||||
// (new File(encDir)).mkdir();
|
||||
// for (int layer = 0; layer < layers; layer++){
|
||||
// (new File(proofsDir +"/layer" + layer )).mkdir();
|
||||
// (new File(encDir +"/layer" + layer )).mkdir();
|
||||
// }
|
||||
// (new File(encDir +"/input")).mkdir();
|
||||
//
|
||||
//
|
||||
// for (int layer = 0; layer < layers; layer++){
|
||||
// for(int i = 0; i < proofs[layer].length; i ++){
|
||||
// writeProofToFile(proofsDir,proofs[layer][i]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (int layer = 0; layer <= layers; layer++){
|
||||
// for(int i = 0; i < encryptedMessages[layer].length; i ++){
|
||||
// writeEncToFile(encDir,layer - 1, i,encryptedMessages[layer][i]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* create new file contains single proof
|
||||
|
@ -91,19 +93,19 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
|||
* @param proof
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
|
||||
Mixing.Mix2Proof.Location location = proof.getLocation();
|
||||
int layer = location.getLayer();
|
||||
int i = location.getI();
|
||||
int j = location.getJ();
|
||||
String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
|
||||
|
||||
File file = new File(fileName);
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(proof.toByteArray());
|
||||
fos.close();
|
||||
}
|
||||
// private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException {
|
||||
// Mixing.Mix2Proof.Location location = proof.getLocation();
|
||||
// int layer = location.getLayer();
|
||||
// int i = location.getI();
|
||||
// int j = location.getJ();
|
||||
// String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
|
||||
//
|
||||
// File file = new File(fileName);
|
||||
// file.createNewFile();
|
||||
// FileOutputStream fos = new FileOutputStream(file);
|
||||
// fos.write(proof.toByteArray());
|
||||
// fos.close();
|
||||
// }
|
||||
|
||||
/**
|
||||
* create new file contains single encrypted message
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
public class ECElGamalMixParams {
|
||||
public class ECElGamalMixStatementGenerator {
|
||||
|
||||
final ECElGamalEncryption encryptor;
|
||||
final ECGroup group;
|
||||
|
@ -31,7 +31,7 @@ public class ECElGamalMixParams {
|
|||
* @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
|
||||
* second base (h) are taken from the encryptor (second base is the public key)
|
||||
*/
|
||||
public ECElGamalMixParams(ECElGamalEncryption encryptor){
|
||||
public ECElGamalMixStatementGenerator(ECElGamalEncryption encryptor){
|
||||
this.encryptor = encryptor;
|
||||
this.group = encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
|
@ -40,11 +40,6 @@ public class ECElGamalMixParams {
|
|||
this.hEncoded = encryptor.encodeElement(h);
|
||||
}
|
||||
|
||||
public enum TrueCouple {
|
||||
left, right, unknown
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* can be used by anyone, e.g meerkat.mixer.verifier
|
||||
*
|
||||
|
@ -84,7 +79,7 @@ public class ECElGamalMixParams {
|
|||
*
|
||||
* The actual stored data is a cached representation for use in proofs and verification. This consists of the four substatements that are ORs of the DLOG equality.
|
||||
*
|
||||
* A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixParams (all constructors are private)
|
||||
* A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixStatementGenerator (all constructors are private)
|
||||
*
|
||||
*/
|
||||
public class Mix2Statement {
|
||||
|
@ -180,9 +175,9 @@ public class ECElGamalMixParams {
|
|||
|
||||
|
||||
DlogStatement(ECPoint a, ECPoint b) {
|
||||
this.g = ECElGamalMixParams.this.g;
|
||||
this.g = ECElGamalMixStatementGenerator.this.g;
|
||||
this.a = a;
|
||||
this.h = ECElGamalMixParams.this.h;
|
||||
this.h = ECElGamalMixStatementGenerator.this.h;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
|
@ -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 meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
@ -26,8 +25,7 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
private final ECElGamalEncryption encryptor;
|
||||
private final ECPoint g,h;
|
||||
private final BigInteger groupOrderUpperBound;
|
||||
private final ECElGamalMixParams mixParams;
|
||||
final ECElGamalMixProtocols mixProtocols;
|
||||
private final ECElGamalMixStatementGenerator mixParams;
|
||||
final SigmaFiatShamir<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> mix2NIZK;
|
||||
|
||||
/**
|
||||
|
@ -43,9 +41,8 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
this.group = this.encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
this.h = this.encryptor.getElGamalPK().getPK();
|
||||
this.mixParams = new ECElGamalMixParams(encryptor);
|
||||
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
|
||||
this.groupOrderUpperBound = group.orderUpperBound();
|
||||
this.mixProtocols = new ECElGamalMixProtocols(mixParams, rand); // We don't need randomness for the verifier
|
||||
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
|
||||
}
|
||||
|
||||
|
@ -55,8 +52,6 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
* @param c - if switched then c = rerandomize(b,r2) else c = rerandomize(a,r1)
|
||||
* @param d - if switched then d = rerandomize(a,r1) else d = rerandomize(b,r2)
|
||||
* @param switched - trueClauseIndex
|
||||
* @param i - column of a and c in encryption table
|
||||
* @param j - column of b and d in encryption table
|
||||
* @param layer - row of a,b in encryption table
|
||||
* @param r1
|
||||
* @param r2
|
||||
|
@ -67,186 +62,25 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
Crypto.RerandomizableEncryptedMessage b,
|
||||
Crypto.RerandomizableEncryptedMessage c,
|
||||
Crypto.RerandomizableEncryptedMessage d,
|
||||
boolean switched,int i,int j, int layer,
|
||||
boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx,
|
||||
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
||||
|
||||
|
||||
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(a,b,c,d);
|
||||
ECElGamalMixParams.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
|
||||
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(a, b, c, d);
|
||||
ECElGamalMixStatementGenerator.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
|
||||
|
||||
ECElGamalMixProtocols.Mix2Prover prover = mixProtocols.new Mix2Prover(statement, witness);
|
||||
Mix2.Prover prover = new Mix2.Prover(encryptor, rand, statement, witness);
|
||||
|
||||
Mixing.Mix2Proof.Location location = Mixing.Mix2Proof.Location.newBuilder()
|
||||
.setI(i)
|
||||
.setJ(j)
|
||||
.setLayer(layer).build();
|
||||
.setLayer(layer)
|
||||
.setSwitchIdx(switchIdx)
|
||||
.setOut0(out0Idx)
|
||||
.setOut1(out1Idx)
|
||||
.build();
|
||||
return mix2NIZK.generateNizk(prover).toBuilder().setLocation(location).build();
|
||||
|
||||
// Mixing.Mix2Proof first,second,third,fourth;
|
||||
//
|
||||
// ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched);
|
||||
//
|
||||
// first = createOrProof(statement.getDlogStatement(0));
|
||||
// second = createOrProof(statement.getDlogStatement(1));
|
||||
// third = createOrProof(statement.getDlogStatement(2));
|
||||
// fourth = createOrProof(statement.getDlogStatement(3));
|
||||
//
|
||||
// Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
|
||||
// .setI(i)
|
||||
// .setJ(j)
|
||||
// .setLayer(layer)
|
||||
// .build();
|
||||
//
|
||||
// Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder()
|
||||
// .setFirst(first)
|
||||
// .setSecond(second)
|
||||
// .setThird(third)
|
||||
// .setFourth(fourth)
|
||||
// .setLocation(location)
|
||||
// .build();
|
||||
// return result;
|
||||
}
|
||||
//
|
||||
//
|
||||
// Mixing.Mix2Proof.DlogProof.FirstMessage createDlogProof(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) {
|
||||
//
|
||||
// BigInteger r = encryptor.generateRandomExponent(rand);
|
||||
// ECPoint gr = group.multiply(statement.g, r);
|
||||
// ECPoint hr = group.multiply(statement.h, r);
|
||||
//
|
||||
// Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder()
|
||||
// .setGr(group.encode(gr))
|
||||
// .setHr(group.encode(hr))
|
||||
// .build();
|
||||
//
|
||||
// BigInteger challenge = Prover.hash()
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Generate a ZK proof that there exists x s.t (g ^ x == a and h ^ x == b) or (g' ^ x == a and h' ^ x == b).
|
||||
// *
|
||||
// * For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g}(a)==log_{g}(b)):
|
||||
// * <ol>
|
||||
// * <li>Prover chooses a random r, and sends g^r, h^r </li>
|
||||
// * <li>Verifier chooses a random c and sends c</li>
|
||||
// * <li>Prover computes </li>
|
||||
// * </ol>
|
||||
// *
|
||||
// *
|
||||
// * @param orStatement
|
||||
// * @return ZKP OrProof:
|
||||
// * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs
|
||||
// */
|
||||
// private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) {
|
||||
//
|
||||
// ECPoint g1 = orStatement.g1;
|
||||
// ECPoint h1 = orStatement.h1;
|
||||
// ECPoint g2 = orStatement.g2;
|
||||
// ECPoint h2 = orStatement.h2;
|
||||
//
|
||||
// ECPoint g1Tag = orStatement.g1Tag;
|
||||
// ECPoint h1Tag = orStatement.h1Tag;
|
||||
// ECPoint g2Tag = orStatement.g2Tag;
|
||||
// ECPoint h2Tag = orStatement.h2Tag;
|
||||
//
|
||||
// // Randomness for the ZK proof
|
||||
// BigInteger r = encryptor.generateRandomExponent(rand);
|
||||
//
|
||||
//
|
||||
// BigInteger c1,c2,z,zTag;
|
||||
// ECPoint u,v,uTag,vTag;
|
||||
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
|
||||
//
|
||||
//
|
||||
// switch (orStatement.trueClauseIndex) {
|
||||
// case left:
|
||||
// c2 = encryptor.generateRandomExponent(rand);
|
||||
// zTag = encryptor.generateRandomExponent(rand);
|
||||
// //step 1
|
||||
// u = group.multiply(g1, r);
|
||||
// v = group.multiply(g2, r);
|
||||
// uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2)));
|
||||
// vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2)));
|
||||
// //step 2
|
||||
// // c1 = (hash(input + step1) + group size - c2)% group size
|
||||
// firstMessage =
|
||||
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
|
||||
// .setG1(orStatement.g1Encoded)
|
||||
// .setH1(orStatement.h1Encoded)
|
||||
// .setG2(orStatement.g2Encoded)
|
||||
// .setH2(orStatement.h2Encoded)
|
||||
// .setG1Tag(orStatement.g1TagEncoded)
|
||||
// .setH1Tag(orStatement.h1TagEncoded)
|
||||
// .setG2Tag(orStatement.g2TagEncoded)
|
||||
// .setH2Tag(orStatement.h2TagEncoded)
|
||||
// .setU(encryptor.encodeElement(u))
|
||||
// .setV(encryptor.encodeElement(v))
|
||||
// .setUTag(encryptor.encodeElement(uTag))
|
||||
// .setVTag(encryptor.encodeElement(vTag))
|
||||
// .build();
|
||||
// c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
|
||||
// //step 3
|
||||
// //z = (r + c1 * x) % group size;
|
||||
// z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
|
||||
// break;
|
||||
// case right:
|
||||
// c1 = encryptor.generateRandomExponent(rand);
|
||||
// z = encryptor.generateRandomExponent(rand);
|
||||
// //step 1
|
||||
// uTag = group.multiply(g1Tag, r);
|
||||
// vTag = group.multiply(g2Tag, r);
|
||||
// u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1)));
|
||||
// v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1)));
|
||||
// //step 2
|
||||
// // c1 = (hash(input + step1) + group size - c1)% group size
|
||||
// firstMessage =
|
||||
// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
|
||||
// .setG1(orStatement.g1Encoded)
|
||||
// .setH1(orStatement.h1Encoded)
|
||||
// .setG2(orStatement.g2Encoded)
|
||||
// .setH2(orStatement.h2Encoded)
|
||||
// .setG1Tag(orStatement.g1TagEncoded)
|
||||
// .setH1Tag(orStatement.h1TagEncoded)
|
||||
// .setG2Tag(orStatement.g2TagEncoded)
|
||||
// .setH2Tag(orStatement.h2TagEncoded)
|
||||
// .setU(encryptor.encodeElement(u))
|
||||
// .setV(encryptor.encodeElement(v))
|
||||
// .setUTag(encryptor.encodeElement(uTag))
|
||||
// .setVTag(encryptor.encodeElement(vTag))
|
||||
// .build();
|
||||
// c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
|
||||
// //step 3
|
||||
// //zTag = (r + c2 * x) % group size;
|
||||
// zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
|
||||
// break;
|
||||
// default:
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
|
||||
// .setG1(firstMessage.getG1())
|
||||
// .setH1(firstMessage.getH1())
|
||||
// .setG2(firstMessage.getG2())
|
||||
// .setH2(firstMessage.getH2())
|
||||
// .setG1Tag(firstMessage.getG1())
|
||||
// .setH1Tag(firstMessage.getH1Tag())
|
||||
// .setG2Tag(firstMessage.getG2Tag())
|
||||
// .setH2Tag(firstMessage.getH2Tag())
|
||||
// .setU(firstMessage.getU())
|
||||
// .setV(firstMessage.getV())
|
||||
// .setUTag(firstMessage.getUTag())
|
||||
// .setVTag(firstMessage.getVTag())
|
||||
// .setC1(Util.encodeBigInteger(c1))
|
||||
// .setC2(Util.encodeBigInteger(c2))
|
||||
// .setZ(Util.encodeBigInteger(z))
|
||||
// .setZTag(Util.encodeBigInteger(zTag))
|
||||
// .build();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 FirstMsgType getFirstMessage();
|
||||
public FinalMessageType getFinalMessage(BigInteger challenge);
|
||||
|
||||
/**
|
||||
* Reset the prover (so the next calls to {@link #getFirstMessage()} will
|
||||
* start a new proof.
|
||||
*/
|
||||
public void reset();
|
||||
}
|
||||
|
||||
public interface Simulator <FirstMsgType, FinalMessageType> {
|
||||
public FirstMsgType getFirstMessage(BigInteger challenge);
|
||||
public FinalMessageType getFinalMessage();
|
||||
|
||||
/**
|
||||
* Reset the prover (so the next calls to {@link #getFirstMessage(BigInteger)} will
|
||||
* start a new proof.
|
||||
*/
|
||||
public void reset();
|
||||
}
|
||||
|
||||
public interface Verifier <FirstMsgType, FinalMessageType> {
|
||||
|
|
|
@ -29,10 +29,6 @@ public class SigmaProtocolAnd2 {
|
|||
public FinalMessageOut getFinalMessage(BigInteger challenge) {
|
||||
return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(challenge));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reset() { provers[0].reset(); provers[1].reset(); }
|
||||
}
|
||||
|
||||
static public class Verifier<FirstMessageOut, FirstMessageIn,
|
||||
|
@ -80,8 +76,6 @@ public class SigmaProtocolAnd2 {
|
|||
return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() { simulators[0].reset(); simulators[1].reset(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,9 +72,6 @@ public class SigmaProtocolOr2 {
|
|||
return finalMessageConcatenator.concatenate(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() { prover.reset(); simulator.reset(); simChallenge = null; }
|
||||
}
|
||||
|
||||
static public class Verifier <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
|
@ -142,9 +139,6 @@ public class SigmaProtocolOr2 {
|
|||
public FinalMessageOut getFinalMessage() {
|
||||
return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() { simulators[0].reset(); simulators[1].reset(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import meerkat.protobuf.Mixing;
|
|||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.RandomOracle;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
|
||||
|
||||
/**
|
||||
* implements Mix2ZeroKnowledgeVerifier
|
||||
|
@ -16,11 +15,11 @@ import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier;
|
|||
public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
||||
|
||||
|
||||
private final ECElGamalEncryption encryptor;
|
||||
private final ECGroup group;
|
||||
private final RandomOracle randomOracle;
|
||||
private final ECPoint g,h;
|
||||
private final ECElGamalMixParams mixParams;
|
||||
final ECElGamalMixProtocols mixProtocols;
|
||||
private final ECElGamalMixStatementGenerator mixParams;
|
||||
final SigmaFiatShamir mix2NIZK;
|
||||
|
||||
|
||||
|
@ -32,12 +31,12 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
|||
* @param randomOracle should be as the random oracle used by meerkat.mixer.proofs
|
||||
*/
|
||||
public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) {
|
||||
this.encryptor = encryptor;
|
||||
this.group = encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
this.h = encryptor.getElGamalPK().getPK();
|
||||
this.randomOracle = randomOracle;
|
||||
this.mixParams = new ECElGamalMixParams(encryptor);
|
||||
this.mixProtocols = new ECElGamalMixProtocols(mixParams, null); // We don't need randomness for the verifier
|
||||
this.mixParams = new ECElGamalMixStatementGenerator(encryptor);
|
||||
this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle);
|
||||
// this.parser = new ZeroKnowledgeOrProofParser(group);
|
||||
}
|
||||
|
@ -60,8 +59,8 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
|||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException {
|
||||
|
||||
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||
Mix2Verifier verifier = mixProtocols.new Mix2Verifier(statement);
|
||||
ECElGamalMixStatementGenerator.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||
Mix2.Verifier verifier = new Mix2.Verifier(encryptor, statement);
|
||||
|
||||
return mix2NIZK.verifyNizk(proof, verifier);
|
||||
}
|
||||
|
|
|
@ -16,20 +16,17 @@ public final class VerifyTable {
|
|||
/**
|
||||
* constructor
|
||||
* @param verifier
|
||||
* @param n
|
||||
* @param mixerOutput
|
||||
* @return true iff the meerkat.mixer.mixing output is valid
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier,int n,MixerOutput mixerOutput)
|
||||
public static boolean verifyTable(Mix2ZeroKnowledgeVerifier verifier, MixerOutput mixerOutput)
|
||||
throws InvalidProtocolBufferException {
|
||||
int index1,index2,layer;
|
||||
int out0,out1,layer, switchIdx;
|
||||
|
||||
//assert n = 2^k
|
||||
if ( (n &(n-1)) != 0)
|
||||
throw new IllegalArgumentException("n");
|
||||
|
||||
int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1;
|
||||
int layers = mixerOutput.getNumLayers();
|
||||
int n = 1 << mixerOutput.getLogN();
|
||||
//initialize locationChecksum table
|
||||
// use for check BeneshNet validity
|
||||
boolean[][] locationChecksum = new boolean[layers][n];
|
||||
|
@ -44,36 +41,32 @@ public final class VerifyTable {
|
|||
for (int j = 0; j < Mix2Proofs[i].length ; j ++){
|
||||
Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
|
||||
Mixing.Mix2Proof.Location location = zkp.getLocation();
|
||||
index1 = location.getI();
|
||||
index2 = location.getJ();
|
||||
out0 = location.getOut0();
|
||||
out1 = location.getOut1();
|
||||
layer = location.getLayer();
|
||||
switchIdx = location.getSwitchIdx();
|
||||
|
||||
// check location validity
|
||||
if (layer > layers >> 1) {
|
||||
if (index2 - index1 != n >> (layers - layer))
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
if (index2 - index1 != n >> (layer + 1))
|
||||
return false;
|
||||
}
|
||||
// TODO: add check
|
||||
// if (layer > layers >> 1) {
|
||||
// if (out1 - out0 != n >> (layers - layer))
|
||||
// return false;
|
||||
// }
|
||||
// else{
|
||||
// if (out1 - out0 != n >> (layer + 1))
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// mark location in table
|
||||
locationChecksum[layer][index1] = true;
|
||||
locationChecksum[layer][index2] = true;
|
||||
locationChecksum[layer][2 * switchIdx] = true;
|
||||
locationChecksum[layer][2 * switchIdx + 1] = true;
|
||||
|
||||
// verify proof
|
||||
if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
||||
rerandomizableEncryptedMessages[layer][index2],
|
||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
||||
if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx],
|
||||
rerandomizableEncryptedMessages[layer][2 * switchIdx + 1],
|
||||
rerandomizableEncryptedMessages[layer + 1][out0],
|
||||
rerandomizableEncryptedMessages[layer + 1][out1],
|
||||
zkp)) {
|
||||
|
||||
verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
||||
rerandomizableEncryptedMessages[layer][index2],
|
||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
||||
zkp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@ option java_package = "meerkat.protobuf";
|
|||
import 'meerkat/crypto.proto';
|
||||
import 'meerkat/concrete_crypto.proto';
|
||||
|
||||
message MixBatchHeader {
|
||||
int32 logN = 1; // log (base 2) of number of inputs to mix
|
||||
int32 layers = 2; // Number of layers in mix
|
||||
}
|
||||
|
||||
message Plaintext {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
@ -44,13 +49,19 @@ message Mix2Proof {
|
|||
BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0
|
||||
}
|
||||
|
||||
message Location{
|
||||
int32 i = 1;
|
||||
int32 j = 2;
|
||||
int32 layer = 3;
|
||||
|
||||
// Location of the
|
||||
message Location {
|
||||
int32 layer = 1; // layer in which the switch is placed
|
||||
int32 switchIdx = 2; // idx of the switch
|
||||
int32 out0 = 3; // idx of the first output ciphertext (in layer+1 of the ciphertext matrix)
|
||||
int32 out1 = 4; // idx of the second output ciphertext (in layer+1 of the ciphertext matrix)
|
||||
}
|
||||
|
||||
|
||||
FirstMessage firstMessage = 1;
|
||||
FinalMessage finalMessage = 2;
|
||||
Location location = 5;
|
||||
}
|
||||
|
||||
|
|
@ -1,100 +1,100 @@
|
|||
package meerkat.mixer;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.mixer.mixing.Mixer;
|
||||
import meerkat.mixer.mixing.MixerOutput;
|
||||
import meerkat.mixer.proofs.Prover;
|
||||
import meerkat.mixer.proofs.Verifier;
|
||||
import meerkat.mixer.proofs.VerifyTable;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
import org.factcenter.qilin.primitives.RandomOracle;
|
||||
import org.factcenter.qilin.primitives.concrete.DigestOracle;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/19/2016.
|
||||
*/
|
||||
public class CreateTestVector {
|
||||
|
||||
|
||||
ECElGamalEncryption encryptor;
|
||||
ECGroup group;
|
||||
Random random,randomMixer,randomProver;
|
||||
RandomOracle randomOracle;
|
||||
Mix2ZeroKnowledgeVerifier verifier;
|
||||
Mix2ZeroKnowledgeProver prover;
|
||||
meerkat.crypto.mixnet.Mixer mixer;
|
||||
private int layers;
|
||||
private int n;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws InvalidKeySpecException {
|
||||
// initialization
|
||||
random = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
encryptor = new ECElGamalEncryption();
|
||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
randomMixer = new Random();
|
||||
randomProver = new Random();
|
||||
randomOracle = new DigestOracle();
|
||||
verifier = new Verifier(encryptor,randomOracle);
|
||||
prover = new Prover(randomProver,encryptor,randomOracle);
|
||||
mixer = new Mixer(prover,encryptor);
|
||||
|
||||
// generate n
|
||||
int logN = 10; // + random.nextInt(8)
|
||||
layers = 2*logN - 1;
|
||||
n = 1 << logN;
|
||||
}
|
||||
|
||||
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
|
||||
List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
|
||||
Voting.PlaintextBallot msg;
|
||||
for (int i = 0; i < n ; i++){
|
||||
msg = Utils.genRandomBallot(2,3,16);
|
||||
result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//@SimpleRerandomizeTest
|
||||
public void createValidTest() throws IOException {
|
||||
|
||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
System.out.println("start mixing");
|
||||
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
|
||||
System.out.println("mixing ended, start verification");
|
||||
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
System.out.println("verification ended, start printing");
|
||||
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
|
||||
System.out.println("all done");
|
||||
}
|
||||
|
||||
//@SimpleRerandomizeTest
|
||||
public void createInvalidTest() throws IOException {
|
||||
|
||||
//Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
|
||||
//Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
|
||||
//mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
|
||||
|
||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
System.out.println("start mixing");
|
||||
MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
|
||||
System.out.println("mixing ended, start negative verification");
|
||||
assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
System.out.println("verification ended, start printing");
|
||||
mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
|
||||
System.out.println("all done");
|
||||
}
|
||||
}
|
||||
//package meerkat.mixer;
|
||||
//
|
||||
//import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
//import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
//import meerkat.mixer.mixing.Mixer;
|
||||
//import meerkat.mixer.mixing.MixerOutput;
|
||||
//import meerkat.mixer.proofs.Prover;
|
||||
//import meerkat.mixer.proofs.Verifier;
|
||||
//import meerkat.mixer.proofs.VerifyTable;
|
||||
//import meerkat.protobuf.Crypto;
|
||||
//import meerkat.protobuf.Voting;
|
||||
//import org.factcenter.qilin.primitives.RandomOracle;
|
||||
//import org.factcenter.qilin.primitives.concrete.DigestOracle;
|
||||
//import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
//import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
//import org.junit.Before;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//import java.security.spec.InvalidKeySpecException;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.List;
|
||||
//import java.util.Random;
|
||||
//
|
||||
///**
|
||||
// * Created by Tzlil on 1/19/2016.
|
||||
// */
|
||||
//public class CreateTestVector {
|
||||
//
|
||||
//
|
||||
// ECElGamalEncryption encryptor;
|
||||
// ECGroup group;
|
||||
// Random random,randomMixer,randomProver;
|
||||
// RandomOracle randomOracle;
|
||||
// Mix2ZeroKnowledgeVerifier verifier;
|
||||
// Mix2ZeroKnowledgeProver prover;
|
||||
// meerkat.crypto.mixnet.Mixer mixer;
|
||||
// private int layers;
|
||||
// private int n;
|
||||
//
|
||||
//
|
||||
// @Before
|
||||
// public void setup() throws InvalidKeySpecException {
|
||||
// // initialization
|
||||
// random = new Random();
|
||||
// group = new ECGroup("secp256k1");
|
||||
// encryptor = new ECElGamalEncryption();
|
||||
// encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
// randomMixer = new Random();
|
||||
// randomProver = new Random();
|
||||
// randomOracle = new DigestOracle();
|
||||
// verifier = new Verifier(encryptor,randomOracle);
|
||||
// prover = new Prover(randomProver,encryptor,randomOracle);
|
||||
// mixer = new Mixer(prover,encryptor);
|
||||
//
|
||||
// // generate n
|
||||
// int logN = 10; // + random.nextInt(8)
|
||||
// layers = 2*logN - 1;
|
||||
// n = 1 << logN;
|
||||
// }
|
||||
//
|
||||
// public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
|
||||
// List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
|
||||
// Voting.PlaintextBallot msg;
|
||||
// for (int i = 0; i < n ; i++){
|
||||
// msg = Utils.genRandomBallot(2,3,16);
|
||||
// result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random)));
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
// //@SimpleRerandomizeTest
|
||||
// public void createValidTest() throws IOException {
|
||||
//
|
||||
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
// System.out.println("start mixing");
|
||||
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer);
|
||||
// System.out.println("mixing ended, start verification");
|
||||
// assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
// System.out.println("verification ended, start printing");
|
||||
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test3");
|
||||
// System.out.println("all done");
|
||||
// }
|
||||
//
|
||||
// //@SimpleRerandomizeTest
|
||||
// public void createInvalidTest() throws IOException {
|
||||
//
|
||||
// //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true);
|
||||
// //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true);
|
||||
// //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
|
||||
//
|
||||
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
// System.out.println("start mixing");
|
||||
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random);
|
||||
// System.out.println("mixing ended, start negative verification");
|
||||
// assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
// System.out.println("verification ended, start printing");
|
||||
// mixerOutput.outToFolder("C:\\Users\\Tzlil\\Desktop\\TestVector\\Test5");
|
||||
// System.out.println("all done");
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -77,7 +77,7 @@ public class Mix2ProofTest extends ECParamTestBase {
|
|||
group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));
|
||||
|
||||
|
||||
Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2);
|
||||
Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0, 0, r1,r2);
|
||||
|
||||
assertTrue (verifier.verify(e1,e2,e1New,e2New, proof));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
// generate n
|
||||
int logN = 9; // + random.nextInt(8)
|
||||
int logN = 5; // + random.nextInt(8)
|
||||
layers = 2*logN - 1;
|
||||
n = 1 << logN;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public class MixingTest extends ECParamTestBase {
|
|||
System.out.println("start verification");
|
||||
startTime = System.currentTimeMillis();
|
||||
|
||||
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
assert (VerifyTable.verifyTable(verifier,mixerOutput));
|
||||
|
||||
finishTime = System.currentTimeMillis();
|
||||
System.out.println(" that took: "+(finishTime-startTime)+ " ms");
|
||||
|
|
|
@ -11,8 +11,8 @@ import java.math.BigInteger;
|
|||
public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
|
||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||
|
||||
ECElGamalMixParams.DlogStatement s1, s2;
|
||||
ECElGamalMixParams.DlogStatementWitness w1, w2;
|
||||
ECElGamalMixStatementGenerator.DlogStatement s1, s2;
|
||||
ECElGamalMixStatementGenerator.DlogStatementWitness w1, w2;
|
||||
|
||||
public DlogAndStatementSigmaTest() {
|
||||
this.dlogtest = new DlogStatementSchnorrSigmaTest();
|
||||
|
@ -20,10 +20,10 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
|
|||
|
||||
@Override
|
||||
void generateRandomTrueStatement() {
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
s1 = s1w1.a; w1 = s1w1.b;
|
||||
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
s2 = s2w2.a; w2 = s2w2.b;
|
||||
}
|
||||
|
||||
|
@ -36,19 +36,19 @@ public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proo
|
|||
@Override
|
||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
|
||||
return new SigmaProtocolAnd2.Prover<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
||||
dlogtest.prots.new DlogStatementSchnorrProver(s1, w1), dlogtest.prots.new DlogStatementSchnorrProver(s2, w2));
|
||||
new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s1, w1), new SchnorrDlogEquivalence.Prover(dlogtest.encryptor, rand, s2, w2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewVerifier() {
|
||||
return new SigmaProtocolAnd2.Verifier<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
||||
dlogtest.prots.new DlogStatementSchnorrVerifier(s1), dlogtest.prots.new DlogStatementSchnorrVerifier(s2));
|
||||
new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s1), new SchnorrDlogEquivalence.Verifier(dlogtest.encryptor, s2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewSimulator() {
|
||||
return new SigmaProtocolAnd2.Simulator<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
||||
dlogtest.prots.new DlogStatementSchnorrSimulator(s1), dlogtest.prots.new DlogStatementSchnorrSimulator(s2));
|
||||
new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s1), new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s2));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,8 +11,8 @@ import java.math.BigInteger;
|
|||
public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> {
|
||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||
|
||||
final ECElGamalMixParams.AndStatement[] statements = new ECElGamalMixParams.AndStatement[2];
|
||||
ECElGamalMixParams.AndStatementWitness w;
|
||||
final ECElGamalMixStatementGenerator.AndStatement[] statements = new ECElGamalMixStatementGenerator.AndStatement[2];
|
||||
ECElGamalMixStatementGenerator.AndStatementWitness w;
|
||||
int trueStatementIndex;
|
||||
|
||||
|
||||
|
@ -23,53 +23,57 @@ public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof
|
|||
@Override
|
||||
void generateRandomTrueStatement() {
|
||||
trueStatementIndex = rand.nextInt(2);
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
ECElGamalMixParams.AndStatement trueStatement = dlogtest.params.new AndStatement(s1w1.a, s2w2.a);
|
||||
w = dlogtest.params.new AndStatementWitness(s1w1.b, s2w2.b);
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
ECElGamalMixStatementGenerator.AndStatement trueStatement = dlogtest.statementGenerator.new AndStatement(s1w1.a, s2w2.a);
|
||||
w = dlogtest.statementGenerator.new AndStatementWitness(s1w1.b, s2w2.b);
|
||||
statements[trueStatementIndex] = trueStatement;
|
||||
|
||||
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
|
||||
ECElGamalMixParams.AndStatement falseStatement = dlogtest.params.new AndStatement(f1, f2);
|
||||
ECElGamalMixStatementGenerator.AndStatement falseStatement = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||
|
||||
statements[1 - trueStatementIndex] = falseStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
void generateRandomFalseStatement() {
|
||||
ECElGamalMixParams.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixParams.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixStatementGenerator.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
ECElGamalMixStatementGenerator.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
|
||||
statements[0] = dlogtest.params.new AndStatement(f1, f2);
|
||||
statements[0] = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||
|
||||
f1 = dlogtest.returnRandomFalseStatement();
|
||||
f2 = dlogtest.returnRandomFalseStatement();
|
||||
statements[1] = dlogtest.params.new AndStatement(f1, f2);
|
||||
statements[1] = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewProver() {
|
||||
SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andProver = dlogtest.prots.new AndStatementProver(statements[trueStatementIndex], w);
|
||||
SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andSimulator = dlogtest.prots.new AndStatementSimulator(statements[1 - trueStatementIndex]);
|
||||
SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andProver = new DlogConjunction.Prover(dlogtest.encryptor, rand, statements[trueStatementIndex], w);
|
||||
SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> andSimulator = new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1 - trueStatementIndex]);
|
||||
|
||||
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
|
||||
return new SigmaProtocolOr2.Prover<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||
dlogtest.prots.challengeGenerator, andProver, andSimulator, trueStatementIndex);
|
||||
gen, andProver, andSimulator, trueStatementIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewVerifier() {
|
||||
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
|
||||
return new SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage,
|
||||
Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||
dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementVerifier(statements[0]), dlogtest.prots.new AndStatementVerifier(statements[1]));
|
||||
gen, new DlogConjunction.Verifier(dlogtest.encryptor, statements[0]), new DlogConjunction.Verifier(dlogtest.encryptor, statements[1]));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> getNewSimulator() {
|
||||
|
||||
Mix2.ChallengeGenerator gen = new Mix2.ChallengeGenerator(dlogtest.encryptor, rand);
|
||||
return new SigmaProtocolOr2.Simulator<>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||
dlogtest.prots.challengeGenerator, dlogtest.prots.new AndStatementSimulator(statements[0]),
|
||||
dlogtest.prots.new AndStatementSimulator(statements[1]));
|
||||
gen, new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[0]),
|
||||
new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1]));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.ECParamTestBase;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
@ -13,42 +15,44 @@ import java.math.BigInteger;
|
|||
public class DlogStatementSchnorrSigmaTest extends
|
||||
SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
||||
|
||||
ECParamTestBase ecParams = new ECParamTestBase();
|
||||
ECElGamalMixParams params;
|
||||
ECElGamalMixProtocols prots;
|
||||
ECParamTestBase ecParams;
|
||||
ECElGamalMixStatementGenerator statementGenerator;
|
||||
ECElGamalEncryption encryptor;
|
||||
ECGroup group;
|
||||
|
||||
ECElGamalMixParams.DlogStatement statement;
|
||||
ECElGamalMixParams.DlogStatementWitness witness;
|
||||
ECElGamalMixProtocols.DlogStatementSchnorrProver prover;
|
||||
ECElGamalMixProtocols.DlogStatementSchnorrVerifier verifier;
|
||||
ECElGamalMixProtocols.DlogStatementSchnorrSimulator simulator;
|
||||
ECElGamalMixStatementGenerator.DlogStatement statement;
|
||||
ECElGamalMixStatementGenerator.DlogStatementWitness witness;
|
||||
SchnorrDlogEquivalence.Prover prover;
|
||||
SchnorrDlogEquivalence.Verifier verifier;
|
||||
SchnorrDlogEquivalence.Simulator simulator;
|
||||
|
||||
public DlogStatementSchnorrSigmaTest() {
|
||||
|
||||
this.params = new ECElGamalMixParams(ecParams.enc);
|
||||
this.prots = new ECElGamalMixProtocols(params, rand); // We don't need randomness for the verifier
|
||||
ecParams = new ECParamTestBase();
|
||||
encryptor = ecParams.enc;
|
||||
group = encryptor.getGroup();
|
||||
this.statementGenerator = new ECElGamalMixStatementGenerator(ecParams.enc);
|
||||
}
|
||||
|
||||
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> returnRandomTrueStatement() {
|
||||
BigInteger x = prots.encryptor.generateRandomExponent(rand);
|
||||
ECPoint a = prots.group.multiply(prots.g, x);
|
||||
ECPoint b = prots.group.multiply(prots.h, x);
|
||||
ECElGamalMixParams.DlogStatement statement = params.new DlogStatement(a, b);
|
||||
ECElGamalMixParams.DlogStatementWitness witness = params.new DlogStatementWitness(x);
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> returnRandomTrueStatement() {
|
||||
BigInteger x = encryptor.generateRandomExponent(rand);
|
||||
ECPoint a = group.multiply(statementGenerator.g, x);
|
||||
ECPoint b = group.multiply(statementGenerator.h, x);
|
||||
ECElGamalMixStatementGenerator.DlogStatement statement = statementGenerator.new DlogStatement(a, b);
|
||||
ECElGamalMixStatementGenerator.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x);
|
||||
|
||||
return new Pair<>(statement, witness);
|
||||
}
|
||||
|
||||
ECElGamalMixParams.DlogStatement returnRandomFalseStatement() {
|
||||
ECPoint a = prots.group.sample(rand);
|
||||
ECPoint b = prots.group.sample(rand);
|
||||
ECElGamalMixStatementGenerator.DlogStatement returnRandomFalseStatement() {
|
||||
ECPoint a = group.sample(rand);
|
||||
ECPoint b = group.sample(rand);
|
||||
|
||||
return params.new DlogStatement(a, b);
|
||||
return statementGenerator.new DlogStatement(a, b);
|
||||
}
|
||||
|
||||
void generateRandomTrueStatement() {
|
||||
Pair<ECElGamalMixParams.DlogStatement, ECElGamalMixParams.DlogStatementWitness> sw = returnRandomTrueStatement();
|
||||
Pair<ECElGamalMixStatementGenerator.DlogStatement, ECElGamalMixStatementGenerator.DlogStatementWitness> sw = returnRandomTrueStatement();
|
||||
this.statement = sw.a;
|
||||
this.witness = sw.b;
|
||||
}
|
||||
|
@ -60,24 +64,24 @@ public class DlogStatementSchnorrSigmaTest extends
|
|||
|
||||
@Override
|
||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
|
||||
prover = prots.new DlogStatementSchnorrProver(statement, witness);
|
||||
prover = new SchnorrDlogEquivalence.Prover(encryptor, rand, statement, witness);
|
||||
return prover;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
|
||||
verifier = prots.new DlogStatementSchnorrVerifier(statement);
|
||||
verifier = new SchnorrDlogEquivalence.Verifier(encryptor, statement);
|
||||
return verifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewSimulator() {
|
||||
simulator = prots.new DlogStatementSchnorrSimulator(statement);
|
||||
simulator = new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement);
|
||||
return simulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger getChallengeModulus() {
|
||||
return prots.group.orderUpperBound();
|
||||
return group.orderUpperBound();
|
||||
}
|
||||
}
|
|
@ -34,11 +34,6 @@ public class DummySigmaProof {
|
|||
public BigInteger getFinalMessage(BigInteger challenge) {
|
||||
return challenge.add(r.multiply(x.add(y)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
||||
public static class Verifier implements SigmaProtocol.Verifier<Crypto.BigInteger,BigInteger> {
|
||||
|
||||
|
@ -81,11 +76,6 @@ public class DummySigmaProof {
|
|||
public BigInteger getFinalMessage() {
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class ZeroKnowledgeProof {
|
|||
|
||||
for (int i = 0; i < n*2 ; i +=2){
|
||||
prover.prove(encryptedMessage[i],encryptedMessage[i+1],reencryptedMessage[i],reencryptedMessage[i+1],
|
||||
false,0,0,0,randomnesses[i],randomnesses[i+1]);
|
||||
false,0,0,0, 0, randomnesses[i],randomnesses[i+1]);
|
||||
}
|
||||
|
||||
long finishTime = System.currentTimeMillis();
|
||||
|
|
Loading…
Reference in New Issue