mixer code

mixer
tzlil.gon 2015-11-24 15:39:39 +02:00
parent aa7dd779e1
commit 12ed7a679d
5 changed files with 518 additions and 2 deletions

View File

@ -6,7 +6,45 @@ option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
// TODO:
message ZeroKnowledgeProof {
bytes data = 1;
}
}
//message ZeroKnowledgeProof {
//
// message OrProof{
// message GroupMember{
// required bytes data = 1;
// }
// message BigIntegerMsg{
// required bytes data = 1;
// }
// //input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
// required GroupMember g1 = 1;
// required GroupMember h1 = 2;
// required GroupMember g2 = 3;
// required GroupMember h2 = 4;
// required GroupMember g1Tag = 5;
// required GroupMember h1Tag = 6;
// required GroupMember g2Tag = 7;
// required GroupMember h2Tag = 8;
//
// //calc: u, v, uTag, vTag;
// required GroupMember g2 = 9;
// required GroupMember h2 = 10;
// required GroupMember g1Tag = 11;
// required GroupMember h1Tag = 12;
//
// //generated: c1,c2,z,zTag
// required BigIntegerMsg c1 = 13;
// required BigIntegerMsg c2 = 14;
// required BigIntegerMsg z = 15;
// required BigIntegerMsg zTag = 16;
// }
//
// required OrProof first = 1;
// required OrProof second = 2;
// required OrProof third = 3;
// required OrProof fourth = 4;
//}
//

205
mixer/build.gradle Normal file
View File

@ -0,0 +1,205 @@
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven-publish'
// Uncomment the lines below to define an application
// (this will also allow you to build a "fatCapsule" which includes
// the entire application, including all dependencies in a single jar)
//apply plugin: 'application'
//mainClassName='your.main.ApplicationClass'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "TODO: Add a description"
// Your project version
version = "0.0"
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
dependencies {
// Meerkat common
compile project(':meerkat-common')
// Logging
compile 'org.slf4j:slf4j-api:1.7.7'
runtime 'ch.qos.logback:logback-classic:1.1.2'
runtime 'ch.qos.logback:logback-core:1.1.2'
// Google protobufs
compile 'com.google.protobuf:protobuf-java:3.+'
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
}
/*==== You probably don't have to edit below this line =======*/
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from
// the command line to the JavaExec task.
systemProperties System.properties
}
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
println "Adding $srcDir"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
task mavenCapsule(type: MavenCapsule) {
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule) {
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
}
/*===================================
* Repositories
*===================================*/
repositories {
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
maven {
url nexusRepository
if (isSnapshot) {
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
// Use local maven repository
mavenLocal()
// Use 'maven central' for other dependencies.
mavenCentral()
}
task "info" << {
println "Project: ${project.name}"
println "Description: ${project.description}"
println "--------------------------"
println "GroupId: $groupId"
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
println ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}

View File

@ -0,0 +1,100 @@
package mixer;
import java.util.ArrayList;
import java.util.List;
class Graph
{
private int n;
private Node[] nodes;
protected Graph(int[] permutation){
n = permutation.length; // n = 2^k
createNodes();
createEdges(permutation);
setSwitches();
}
protected boolean getSwitchValue(int index,boolean up)
{
// index must be less then n/2
return up ? nodes[index].on : nodes[index + n / 2].on;
}
private void createNodes()
{
nodes = new Node[n];
for (int i = 0; i < n / 2; i++)
{
nodes[i] = new Node(i, i + n / 2, true);
nodes[i + n / 2] = new Node(i, i + n / 2, false);
}
}
private void createEdges(int[] permutation)
{
int pi1, pi2;
for (int i = 0; i < n / 2; i++)
{
pi1 = (permutation[i] < n / 2) ? permutation[i] + (n / 2) : permutation[i];
pi2 = (permutation[i + n / 2] < n / 2) ? permutation[i + n / 2] + (n / 2) : permutation[i + n / 2];
nodes[i].edges.add(new Edge(nodes[pi1], (permutation[i] >= n / 2)));
nodes[pi1].edges.add(new Edge(nodes[i], (permutation[i] >= n / 2)));
nodes[i].edges.add(new Edge(nodes[pi2], (permutation[i + n / 2] < n / 2)));
nodes[pi2].edges.add(new Edge(nodes[i], (permutation[i + n / 2] < n / 2)));
}
}
private void setSwitches()
{
for (int i = 0; i < n / 2; i++)
{
Node node = nodes[i];
if (node.set)
continue;
boolean v = false;
while (true)
{
node.set = true;
node.on = v;
if (node.edges.get(0).nighbor.set && node.edges.get(1).nighbor.set)
break;
v ^= (!node.edges.get(0).nighbor.set) ? node.edges.get(0).broken : node.edges.get(1).broken;
node = (!node.edges.get(0).nighbor.set) ? node.edges.get(0).nighbor : node.edges.get(1).nighbor;
}
}
}
private class Node
{
public boolean up;
public List<Edge> edges;
public int i, j;
public boolean on;
public boolean set;
public Node(int i, int j,boolean up)
{
this.i = i;
this.j = j;
this.up = up;
edges = new ArrayList<Edge>();
set = false;
}
}
private class Edge
{
public Node nighbor;
public boolean broken;
public Edge(Node nighbor, boolean broken)
{
this.nighbor = nighbor;
this.broken = broken;
}
}
}

View File

@ -0,0 +1,172 @@
package mixer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import com.google.protobuf.InvalidProtocolBufferException;
import javafx.util.Pair;
import java.util.Random;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.Mixing.*;
import meerkat.crypto.Encryption;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
public class Mixer{
private Random random;
private Mix2ZeroKnowledgeProver prover;
private Encryption encryptor;
public Mixer(Random rand,Mix2ZeroKnowledgeProver prov,Encryption enc) {
this.random = rand;
this.prover = prov;
this.encryptor = enc;
}
public Pair<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]> mix(List<RerandomizableEncryptedMessage> ciphertexts) throws InvalidProtocolBufferException{
int n = ciphertexts.size();
// assert n = 2^k and n > 1
if( n <= 1 || ((n & (n-1)) != 0))
return null;
//initialization
int layers = 0;
for (int i = n; i > 1; i>>=1) {
layers++;
}
layers<<=1;
layers--;
RerandomizableEncryptedMessage[][] encryptionsTable = new RerandomizableEncryptedMessage[layers][n];
ZeroKnowledgeProof[][] proofsTable= new ZeroKnowledgeProof[layers][n/2];
boolean[][] mixnet = createMixNet(n,layers);
int index1, index2, switchIndex = 0;
EncryptionRandomness r1 ,r2;
RerandomizableEncryptedMessage e1, e2;
boolean half = true;
//set first level of encryptions
for (int j = 0; j < n; j++)
{
encryptionsTable[0][j] = ciphertexts.get(j);
}
// main loop
for (int i = n, layer = 0; layer < layers; layer++) // i == permutation size
{
for (int j = 0; j < n; j += i) //
{
for (int k = 0; k < i / 2; k++)
{
index1 = k + j;
index2 = k + j + i / 2;
e1 = encryptionsTable[layer][index1];
e2 = encryptionsTable[layer][index2];
r1 = encryptor.generateRandomness(random);
r2 = encryptor.generateRandomness(random);
if (!mixnet[layer][switchIndex])
{
encryptionsTable[layer+1][index1] = encryptor.rerandomize(e1, r1);
encryptionsTable[layer+1][index2] = encryptor.rerandomize(e2,r2);
}
else
{
encryptionsTable[layer+1][index1] = encryptor.rerandomize(e2,r2);
encryptionsTable[layer+1][index2] = encryptor.rerandomize(e1,r1);
}
proofsTable[layer][switchIndex] =
prover.prove(e1, e2, encryptionsTable[layer + 1][index1],
encryptionsTable[layer + 1][index2],
mixnet[layer][switchIndex], r1,r2);
switchIndex = (switchIndex + 1) % (n / 2);
}
}
if (half)
{
i >>= 1;
if (i == 1)
{
half = false;
i = 4;
}
}
else
{
i <<= 1;
}
}
return new Pair<ZeroKnowledgeProof[][],RerandomizableEncryptedMessage[][]>(proofsTable, encryptionsTable);
}
private int[] randomPermutation(int n){
List<Integer> numbers= new ArrayList<Integer>(n);
for (int i = 0; i < n; i++)
{
numbers.add(i);
}
int[] result = new int[n];
int index;
for (int i = 0; i < n; i++)
{
index = random.nextInt(n - i);
result[i] = numbers.get(index);
numbers.remove(index);
}
return result;
}
private boolean[][] createMixNet(int n,int layers)
{
int[] permutaion = randomPermutation(n);
int[] pi, piL, piR;
Queue<int[]> permutaions = new ArrayBlockingQueue<int[]>(n);
Graph graph;
boolean[][] mixnet = new boolean[layers][n>>1];
permutaions.add(permutaion);
for (int i = n, layer = 0; i > 1; i >>= 1, layer++) // i == permutation size
{
for (int j = 0; j < n / 2; j += i / 2) //
{
pi = permutaions.remove();
graph = new Graph(pi);
piL = new int[i / 2];
piR = new int[i / 2];
for (int k = 0; k < i / 2; k++)
{
mixnet[layers - layer - 1][k + j] = graph.getSwitchValue(k, true);
mixnet[layer][k + j] = graph.getSwitchValue(k, false);
if (!mixnet[layers - layer - 1][k + j])
{
piL[k] = pi[k] % (i / 2);
piR[k] = pi[k + i / 2] % (i / 2);
}
else
{
piL[k] = pi[k + i / 2] % (i / 2);
piR[k] = pi[k] % (i / 2);
}
}
permutaions.add(piL);
permutaions.add(piR);
}
}
return mixnet;
}
}

View File

@ -3,3 +3,4 @@ include 'voting-booth'
include 'bulletin-board-server'
include 'polling-station'
include 'restful-api-common'
include 'mixer'