Merge branch 'master' of https://vcs.factcenter.org/meerkat/meerkat-java into voting-booth-gui
commit
17d7d5eca4
53
build.gradle
53
build.gradle
|
@ -1,10 +1,57 @@
|
|||
plugins {
|
||||
id "com.google.osdetector" version "1.4.0"
|
||||
}
|
||||
|
||||
subprojects { proj ->
|
||||
proj.afterEvaluate {
|
||||
// Used to generate initial maven-dir layout
|
||||
task "create-dirs" { description = "Create default maven directory structure" } << {
|
||||
sourceSets*.java.srcDirs*.each { it.mkdirs() }
|
||||
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
|
||||
task "create-dirs" {
|
||||
description = "Create default maven directory structure"
|
||||
doLast {
|
||||
sourceSets*.java.srcDirs*.each { it.mkdirs() }
|
||||
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Script to create a copy of the protobuf compiler jar in the top-level build directory
|
||||
// (will make it easier to configure the intellij protobuf plugin)
|
||||
repositories {
|
||||
mavenLocal();
|
||||
mavenCentral();
|
||||
}
|
||||
|
||||
|
||||
project.ext.protocLocation = 'com.google.protobuf:protoc:3.+'
|
||||
|
||||
// Copied from Google's protobuf plugin code
|
||||
File getProtocDep(protocLocation) {
|
||||
// create a project configuration dependency for the artifact
|
||||
Configuration config = project.configurations.create("protobufToolsLocator") {
|
||||
visible = false
|
||||
transitive = false
|
||||
extendsFrom = []
|
||||
}
|
||||
|
||||
def groupId, artifact, version
|
||||
(groupId, artifact, version) = protocLocation.split(":")
|
||||
def notation = [group: groupId,
|
||||
name: artifact,
|
||||
version: version,
|
||||
classifier: project.osdetector.classifier,
|
||||
ext: 'exe']
|
||||
Dependency dep = project.dependencies.add(config.name, notation)
|
||||
|
||||
File file = config.fileCollection(dep).singleFile
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
|
||||
task getprotoc(type: Copy) {
|
||||
from getProtocDep(project.ext.protocLocation)
|
||||
rename { file -> return "protoc" }
|
||||
into "${buildDir}/"
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,11 @@ ext {
|
|||
|
||||
// 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') : ""
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "TODO: Add a description"
|
||||
|
@ -131,17 +134,19 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
|
||||
destinationDir = buildDir
|
||||
|
||||
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
|
||||
def fatMain
|
||||
|
||||
if (this.hasProperty('fatmain')) {
|
||||
fatMain = fatmain
|
||||
appendix = "fat-${fatMain}"
|
||||
} else {
|
||||
fatMain = mainClassName
|
||||
appendix = "fat"
|
||||
}
|
||||
|
||||
applicationClass fatMain
|
||||
|
||||
def testJar = hasProperty('test')
|
||||
|
||||
if (hasProperty('fatmain')) {
|
||||
appendix = "fat-${fatMain}"
|
||||
} else {
|
||||
appendix = "fat"
|
||||
}
|
||||
def testJar = this.hasProperty('test')
|
||||
|
||||
if (testJar) {
|
||||
from sourceSets.test.output
|
||||
|
@ -205,12 +210,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,11 @@ 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') : ""
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat Voting Common Library"
|
||||
|
@ -38,23 +37,10 @@ dependencies {
|
|||
compile project(':meerkat-common')
|
||||
compile project(':restful-api-common')
|
||||
|
||||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
||||
|
||||
// Databases
|
||||
compile 'org.xerial:sqlite-jdbc:3.7.+'
|
||||
|
||||
// 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.+'
|
||||
|
||||
// Crypto
|
||||
compile 'org.factcenter.qilin:qilin:1.1+'
|
||||
compile 'org.bouncycastle:bcprov-jdk15on:1.53'
|
||||
compile 'org.bouncycastle:bcpkix-jdk15on:1.53'
|
||||
|
||||
// Depend on test resources from meerkat-common
|
||||
testCompile project(path: ':meerkat-common', configuration: 'testOutput')
|
||||
|
||||
|
@ -178,34 +164,22 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
repositories {
|
||||
|
||||
// Use local repo if possible
|
||||
mavenLocal();
|
||||
|
||||
// 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 '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 ""
|
||||
task "info" {
|
||||
doLast {
|
||||
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'
|
||||
|
||||
|
@ -227,12 +201,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../gradlew
|
|
@ -21,13 +21,12 @@ apply plugin: 'maven-publish'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Bulletin-board server web application"
|
||||
|
@ -43,9 +42,6 @@ dependencies {
|
|||
compile project(':meerkat-common')
|
||||
compile project(':restful-api-common')
|
||||
|
||||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
||||
|
||||
// JDBC connections
|
||||
compile 'org.springframework:spring-jdbc:4.2.+'
|
||||
compile 'org.xerial:sqlite-jdbc:3.8.+'
|
||||
|
@ -56,14 +52,6 @@ dependencies {
|
|||
// Servlets
|
||||
compile 'javax.servlet:javax.servlet-api:3.0.+'
|
||||
|
||||
// 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.+'
|
||||
|
||||
// Depend on test resources from meerkat-common
|
||||
testCompile project(path: ':meerkat-common', configuration: 'testOutput')
|
||||
|
||||
|
@ -196,37 +184,24 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
jcenter()
|
||||
//jcenter()
|
||||
|
||||
// Use 'maven central' for other dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -248,12 +223,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,16 +20,16 @@ apply plugin: 'maven-publish'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
|
||||
}
|
||||
|
||||
description = "TODO: Add a description"
|
||||
description = "Distributed key generation code"
|
||||
|
||||
// Your project version
|
||||
version = "0.0"
|
||||
|
@ -41,14 +41,6 @@ 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.+'
|
||||
|
||||
// Depend on test resources from meerkat-common
|
||||
testCompile project(path: ':meerkat-common', configuration: 'testOutput')
|
||||
|
||||
|
@ -99,7 +91,7 @@ idea {
|
|||
|
||||
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
||||
|
||||
println "Adding $srcDir"
|
||||
// println "Adding $srcDir"
|
||||
// add protobuf generated sources to generated source dir.
|
||||
if ("test".equals(sourceSet.name)) {
|
||||
testSourceDirs += file(srcDir)
|
||||
|
@ -158,21 +150,6 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
|
@ -180,13 +157,15 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -208,12 +187,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
|
|||
* setter
|
||||
* @param parties
|
||||
*/
|
||||
protected void setParties(Party[] parties){
|
||||
protected void setParties(Party<T>[] parties){
|
||||
this.parties = parties;
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
|
|||
* getter
|
||||
* @return
|
||||
*/
|
||||
protected Party[] getParties(){
|
||||
protected Party<T>[] getParties(){
|
||||
return parties;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ public class User<T> implements Runnable {
|
|||
* All parties participating in key generation.
|
||||
* parties[id-1] has my info.
|
||||
*/
|
||||
protected final Party[] parties;
|
||||
protected final Party<T>[] parties;
|
||||
|
||||
/**
|
||||
* set of all non-disqualified parties
|
||||
|
|
|
@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip
|
||||
distributionSha256Sum=43be380834a13e28e9504c21f67fe1a8895ab54f314a6596601896dca7213482
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
distributionSha256Sum=71a787faed83c4ef21e8464cc8452b941b5fcd575043aa29d39d15d879be89f7
|
||||
|
|
|
@ -19,13 +19,12 @@ mainClassName='Demo'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat Voting Common Library"
|
||||
|
@ -39,10 +38,12 @@ version += "${isSnapshot ? '-SNAPSHOT' : ''}"
|
|||
dependencies {
|
||||
// Logging
|
||||
compile 'org.slf4j:slf4j-api:1.7.7'
|
||||
compile 'javax.ws.rs:javax.ws.rs-api:2.0.+'
|
||||
runtime 'ch.qos.logback:logback-classic:1.1.2'
|
||||
runtime 'ch.qos.logback:logback-core:1.1.2'
|
||||
|
||||
// RESTful API
|
||||
compile 'javax.ws.rs:javax.ws.rs-api:2.0.+'
|
||||
|
||||
// Google protobufs
|
||||
compile 'com.google.protobuf:protobuf-java:3.+'
|
||||
|
||||
|
@ -157,32 +158,20 @@ task fatCapsule(type: FatCapsule){
|
|||
repositories {
|
||||
|
||||
mavenLocal();
|
||||
|
||||
// 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 'maven central' for other dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -204,12 +193,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,14 @@ import java.util.List;
|
|||
*/
|
||||
public class MessageInputStream<T extends Message> implements Iterable<T>{
|
||||
|
||||
Class<T> type;
|
||||
|
||||
private T.Builder builder;
|
||||
|
||||
private InputStream in;
|
||||
|
||||
MessageInputStream(InputStream in, Class<T> type) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
this.type = type;
|
||||
this.in = in;
|
||||
this.builder = (T.Builder) type.getMethod("newBuilder").invoke(type);
|
||||
}
|
||||
|
@ -41,7 +44,7 @@ public class MessageInputStream<T extends Message> implements Iterable<T>{
|
|||
@Override
|
||||
public T next() {
|
||||
try {
|
||||
return readMessage();
|
||||
return readMessage(type);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
@ -65,12 +68,10 @@ public class MessageInputStream<T extends Message> implements Iterable<T>{
|
|||
|
||||
}
|
||||
|
||||
public T readMessage() throws IOException{
|
||||
|
||||
public T readMessage(Class<T> msgType) throws IOException{
|
||||
builder.clear();
|
||||
builder.mergeDelimitedFrom(in);
|
||||
return (T) builder.build();
|
||||
|
||||
return msgType.cast(builder.build());
|
||||
}
|
||||
|
||||
public boolean isAvailable() throws IOException {
|
||||
|
@ -82,7 +83,7 @@ public class MessageInputStream<T extends Message> implements Iterable<T>{
|
|||
List<T> list = new LinkedList<>();
|
||||
|
||||
while (isAvailable()){
|
||||
list.add(readMessage());
|
||||
list.add(readMessage(type));
|
||||
}
|
||||
|
||||
return list;
|
||||
|
|
|
@ -80,6 +80,45 @@ public class ECElGamalEncryption implements Encryption {
|
|||
elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a group element into a protobuf.
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
public ConcreteCrypto.GroupElement encodeElement(ECPoint p) {
|
||||
return encodeElement(group, p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode a group element into a protobuf.
|
||||
*
|
||||
* @param group group to use for encoding
|
||||
* @param p element to encode.
|
||||
* @return
|
||||
*/
|
||||
public static ConcreteCrypto.GroupElement encodeElement(ECGroup group, ECPoint p) {
|
||||
return ConcreteCrypto.GroupElement.newBuilder().setData(ByteString.copyFrom(p.getEncoded(true))).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode from the serialized representation to an {@link ECPoint} object.
|
||||
* @param bs
|
||||
* @return
|
||||
*/
|
||||
public ECPoint decodeElement(ConcreteCrypto.GroupElement bs) {
|
||||
return decodeElement(group, bs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode from the serialized representation to an {@link ECPoint} object.
|
||||
* @param group group to use for decoding.
|
||||
* @param bs
|
||||
* @return
|
||||
*/
|
||||
public static ECPoint decodeElement(ECGroup group, ConcreteCrypto.GroupElement bs) {
|
||||
return group.decode(bs.getData().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) {
|
||||
|
@ -95,11 +134,11 @@ public class ECElGamalEncryption implements Encryption {
|
|||
byte[] msg = out.toByteArray();
|
||||
ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg));
|
||||
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
BigInteger rndInt = extractRandomness(rnd);
|
||||
Pair<ECPoint,ECPoint> cipherText = elGamalPK.encrypt(encodedMsg, rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(cipherText.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(cipherText.b.getEncoded(true)))
|
||||
.setC1(encodeElement(cipherText.a))
|
||||
.setC2(encodeElement(cipherText.b))
|
||||
.build();
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
|
@ -118,34 +157,49 @@ public class ECElGamalEncryption implements Encryption {
|
|||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException {
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
BigInteger rndInt = extractRandomness(rnd);
|
||||
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
|
||||
|
||||
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
|
||||
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
|
||||
curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
|
||||
decodeElement(originalEncodedCipher.getC1()),
|
||||
decodeElement(originalEncodedCipher.getC2()));
|
||||
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(
|
||||
ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(newCipher.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(newCipher.b.getEncoded(true)))
|
||||
.setC1(encodeElement(newCipher.a))
|
||||
.setC2(encodeElement(newCipher.b))
|
||||
.build().toByteString()
|
||||
).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.EncryptionRandomness generateRandomness(Random rand) {
|
||||
BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand);
|
||||
BigInteger randomInt = generateRandomExponent(rand);
|
||||
Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder()
|
||||
.setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discrete log of a random element in the group (i.e., a random value in Z_{groupOrder})
|
||||
* @param rand
|
||||
* @return
|
||||
*/
|
||||
public BigInteger generateRandomExponent(Random rand) {
|
||||
return new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract (deserialize) the random exponent from a {@link Crypto.EncryptionRandomness} protobuf.
|
||||
*
|
||||
* @param encryptionRandomness
|
||||
* @return
|
||||
*/
|
||||
public BigInteger extractRandomness(Crypto.EncryptionRandomness encryptionRandomness){
|
||||
return new BigInteger(1,encryptionRandomness.getData().toByteArray());
|
||||
return BigIntegers.fromUnsignedByteArray(encryptionRandomness.getData().toByteArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.primitives.generic.ElGamal;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
/**
|
||||
* Created by talm on 02/11/16.
|
||||
*/
|
||||
public class Util {
|
||||
|
||||
public final static String ENCRYPTION_KEY_ALGORITHM = ECElGamalEncryption.KEY_ALGORITHM;
|
||||
|
||||
/**
|
||||
* Decode a BigInteger from a protobuf
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public static BigInteger decodeBigInteger(Crypto.BigInteger i) {
|
||||
return new BigInteger(i.getData().toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a BigInteger in a protobuf.
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public static Crypto.BigInteger encodeBigInteger(BigInteger i) {
|
||||
return Crypto.BigInteger.newBuilder().setData(ByteString.copyFrom(i.toByteArray())).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption}
|
||||
* @param pk
|
||||
* @return
|
||||
*/
|
||||
public static ConcreteCrypto.ElGamalPublicKey encodePK(ECGroup group, ElGamal.PK<ECPoint> pk) {
|
||||
ECPoint pkPoint = pk.getPK();
|
||||
ECParameterSpec params = group.getCurveParams();
|
||||
|
||||
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
|
||||
|
||||
try {
|
||||
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
|
||||
GlobalCryptoSetup.getInstance().getBouncyCastleProvider());
|
||||
PublicKey javaPk = fact.generatePublic(pubKeySpec);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder()
|
||||
.setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build();
|
||||
|
||||
return serializedPk;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error converting public key!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize an ECElGamal secret key.
|
||||
* @param serializedPk
|
||||
* @param serializedSk
|
||||
* @return
|
||||
* @throws InvalidKeySpecException
|
||||
*/
|
||||
public static ECElGamal.SK decodeSK(ConcreteCrypto.ElGamalPublicKey serializedPk, Crypto.BigInteger serializedSk)
|
||||
throws InvalidKeySpecException {
|
||||
ECElGamalEncryption enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
ECElGamal.SK sk = new ECElGamal.SK(enc.getGroup(), decodeBigInteger(serializedSk));
|
||||
return sk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard (non-threshold) decryption for testing purposes.
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ConcreteCrypto.GroupElement c1encoded = cipherText.getC1();
|
||||
ConcreteCrypto.GroupElement c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
|
||||
ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
|
||||
|
||||
assert (group.contains(c1));
|
||||
assert (group.contains(c2));
|
||||
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
|
||||
|
||||
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
|
||||
|
||||
try {
|
||||
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
|
||||
Message.Builder builder = (Message.Builder) newBuilder.invoke(plaintextMessageType);
|
||||
builder.mergeDelimitedFrom(in);
|
||||
return plaintextMessageType.cast(builder.build());
|
||||
} catch (Exception e) {
|
||||
throw new InvalidProtocolBufferException("Plaintext protobuf error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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.ZeroKnowledgeProof 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;
|
||||
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Verify the two-ciphertext mix proof
|
||||
*/
|
||||
public interface Mix2ZeroKnowledgeVerifier {
|
||||
/**
|
||||
* Return true iff the proof is valid.
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @return
|
||||
*/
|
||||
boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.protobuf.Crypto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public interface Mixer {
|
||||
public MixerOutput mix(List<Crypto.RerandomizableEncryptedMessage> ciphertexts,Random random)
|
||||
throws InvalidProtocolBufferException;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/18/2016.
|
||||
*/
|
||||
public interface MixerOutput {
|
||||
public Mixing.ZeroKnowledgeProof[][] getProofs();
|
||||
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages();
|
||||
public int getN();
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Trustee {
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Verifier {
|
||||
}
|
|
@ -10,4 +10,4 @@ message BroadcastMessage {
|
|||
bool is_private = 3;
|
||||
|
||||
bytes payload = 5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,13 @@ message ElGamalPublicKey {
|
|||
bytes subject_public_key_info = 1;
|
||||
}
|
||||
|
||||
// An El-Gamal ciphertext
|
||||
// Each group element should be an ASN.1 encoded curve point with compression.
|
||||
message GroupElement {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
// An El-Gamal ciphertext
|
||||
message ElGamalCiphertext {
|
||||
bytes c1 = 1; // First group element
|
||||
bytes c2 = 2; // Second group element
|
||||
GroupElement c1 = 1; // First group element
|
||||
GroupElement c2 = 2; // Second group element
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package meerkat;
|
||||
|
||||
option java_package = "meerkat.protobuf";
|
||||
|
||||
import 'meerkat/crypto.proto';
|
||||
|
||||
message Plaintext{
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
message ZeroKnowledgeProof {
|
||||
message OrProof {
|
||||
message ForRandomOracle{
|
||||
bytes g1 = 1;
|
||||
bytes h1 = 2;
|
||||
bytes g2 = 3;
|
||||
bytes h2 = 4;
|
||||
bytes g1Tag = 5;
|
||||
bytes h1Tag = 6;
|
||||
bytes g2Tag = 7;
|
||||
bytes h2Tag = 8;
|
||||
bytes u = 9;
|
||||
bytes v = 10;
|
||||
bytes uTag = 11;
|
||||
bytes vTag = 12;
|
||||
}
|
||||
//input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
|
||||
bytes g1 = 1;
|
||||
bytes h1 = 2;
|
||||
bytes g2 = 3;
|
||||
bytes h2 = 4;
|
||||
bytes g1Tag = 5;
|
||||
bytes h1Tag = 6;
|
||||
bytes g2Tag = 7;
|
||||
bytes h2Tag = 8;
|
||||
|
||||
//calc: u, v, uTag, vTag;
|
||||
bytes u = 9;
|
||||
bytes v = 10;
|
||||
bytes uTag = 11;
|
||||
bytes vTag = 12;
|
||||
|
||||
//generated: c1,c2,z,zTag
|
||||
bytes c1 = 13;
|
||||
bytes c2 = 14;
|
||||
bytes z = 15;
|
||||
bytes zTag = 16;
|
||||
}
|
||||
message Location{
|
||||
int32 i = 1;
|
||||
int32 j = 2;
|
||||
int32 layer = 3;
|
||||
}
|
||||
|
||||
OrProof first = 1;
|
||||
OrProof second = 2;
|
||||
OrProof third = 3;
|
||||
OrProof fourth = 4;
|
||||
Location location = 5;
|
||||
}
|
|
@ -123,7 +123,7 @@ message ElectionParams {
|
|||
// Verification keys for valid mixers.
|
||||
repeated SignatureVerificationKey mixerVerificationKeys = 4;
|
||||
|
||||
// How many mixers must participate for the mixing to be considered valid
|
||||
// How many mixers must participate for the network to be considered valid
|
||||
uint32 mixerThreshold = 5;
|
||||
|
||||
// questions to first indicate the voter's channel
|
||||
|
|
|
@ -81,7 +81,7 @@ public class MessageStreamTest {
|
|||
new ByteArrayInputStream(stream.toByteArray()),
|
||||
BulletinBoardMessage.class);
|
||||
|
||||
assertThat("Retrieved message was not identical to send message", comparator.compare(message, in.readMessage()), is(equalTo(0)));
|
||||
assertThat("Retrieved message was not identical to send message", comparator.compare(message, in.readMessage(BulletinBoardMessage.class)), is(equalTo(0)));
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.google.protobuf.GeneratedMessage;
|
|||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.ConcreteCrypto.GroupElement;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
|
@ -66,13 +67,13 @@ public class ECElGamalUtils {
|
|||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ByteString c1encoded = cipherText.getC1();
|
||||
ByteString c2encoded = cipherText.getC2();
|
||||
GroupElement c1encoded = cipherText.getC1();
|
||||
GroupElement c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = group.decode(c1encoded.toByteArray());
|
||||
ECPoint c2 = group.decode(c2encoded.toByteArray());
|
||||
ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
|
||||
ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
|
||||
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<>(c1, c2));
|
||||
|
||||
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
|
||||
|
||||
|
|
|
@ -13,26 +13,25 @@ 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'
|
||||
apply plugin: 'application'
|
||||
mainClassName='meerkat.mixer.main.Mix'
|
||||
|
||||
// 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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "TODO: Add a description"
|
||||
description = "Mix network implementation"
|
||||
|
||||
// Your project version
|
||||
version = "0.0"
|
||||
version = "0.1"
|
||||
|
||||
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
|
||||
|
||||
|
@ -41,16 +40,8 @@ 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.+'
|
||||
|
||||
// Crypto
|
||||
compile 'org.factcenter.qilin:qilin:1.2.+'
|
||||
// Command-line parsing.
|
||||
compile 'net.sf.jopt-simple:jopt-simple:6.+'
|
||||
|
||||
testCompile 'junit:junit:4.+'
|
||||
|
||||
|
@ -84,7 +75,7 @@ idea {
|
|||
|
||||
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
||||
|
||||
println "Adding $srcDir"
|
||||
// println "Adding $srcDir"
|
||||
// add protobuf generated sources to generated source dir.
|
||||
if ("test".equals(sourceSet.name)) {
|
||||
testSourceDirs += file(srcDir)
|
||||
|
@ -143,21 +134,6 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
|
@ -165,13 +141,15 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -193,12 +171,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../meerkat-common/src/main/proto/meerkat/concrete_crypto.proto
|
|
@ -0,0 +1 @@
|
|||
../../meerkat-common/src/main/proto/meerkat/crypto.proto
|
|
@ -0,0 +1,104 @@
|
|||
#Mixer File Format
|
||||
This document attempts to provide sufficient information to write a verifier for our mixnet implementation.
|
||||
|
||||
## High-Level Overview.
|
||||
The mixer implements Abe's Permutation-network-based mix. The on-disk format of the mixer's output consists of a sequence of protobif messages, written using their writeDelimitedTo() method:
|
||||
1. A [MixBatchHeader](mixing.proto) message containing the number of switch layers and the number of ciphertexts in each layer (where the latter is given as the base-2 log of the number, since the actual number must be a power of 2).
|
||||
2. A matrix of ciphertext messages. The matrix is given column by column; the total number of columns is the number of layers + 1 (the first column is the input to the mix, and the final column is the output). The first message in the sequence is ciphertext 0 in column 0, then ciphertext 1 in layer 0, finally ending with ciphertext $2^{logN}-1$ in column $layers$.
|
||||
3. A matrix of proofs for each 2x2 switch. The matrix is given column by column; the total number of columns is the number of layers. The first message in the matrix sequence is switch 0 in column 0, then switch 1 in column 0, finally ending with switch $2^{logN-1}-1$ in column $layers-1$.
|
||||
|
||||
|
||||
## Ciphertexts
|
||||
For future compatibility, each ciphertext actually written to disk is encoded as an "opaque" [RerandomizableEncryptedMessage](crypto.proto). The data field of this message contains the serialized ElGamalCiphertext message (see below).
|
||||
|
||||
### EC-ElGamal Ciphertexts
|
||||
Ciphertexts are serialized using the [ElGamalCiphertext](concrete_crypto.proto) message, with fields "c1" and "c2" for the first and second group elements.
|
||||
|
||||
### EC Group elements
|
||||
Group elements use the [GroupElement](concrete_crypto.proto) message. It's only field is "data", which should be an ASN.1-encoded curve point with compression (see section 4.3.6 of [X9.62-1998](https://www.security-audit.com/files/x9-62-09-20-98.pdf) "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)")
|
||||
|
||||
### EC-ElGamal Key Format
|
||||
The ECElGamal Key is stored in the [ElGamalPublicKey](concrete_crypto.proto) message that contains a standard DER-encoded SubjectPublicKeyInfo as in [RFC 3279](https://tools.ietf.org/html/rfc3279) (note that this encoding includes the elliptic-curve group parameters).
|
||||
|
||||
|
||||
|
||||
## Proofs
|
||||
Each mixing proof is a serialized [Mix2Proof](mixing.proto) message. This consists of a firstMessage field (containing the first message of the Sigma protocol) and a finalMessage field(containing the final message of the Sigma protocol). The challenge is derived from the *serialized form* of the firstMessage field by hashing (see [Fiat-Shamir](#fiat-shamir-random-oracle) below for the hash algorithm), a finalMessage field and a location field (see [Location](#location) below).
|
||||
|
||||
### Proof Statement
|
||||
The proof statement itself is a disjunction of two conjunctions of Schnorr proofs for discrete-log equivalence, constructed from the ciphertexts. Let $g$ be the group generator and $h$ the ElGamal public key. Given input ciphertexts $a=(a_1,a_2)$ and
|
||||
$b=(b_1,b_2)$ and output ciphertexts $c=(c_1,c_2)$ and $d=(d_1,d_2)$, the statement proved is:
|
||||
$$
|
||||
(\log_g \frac{c_1}{a_1} = \log_h\frac{c_2}{a_2})\text{ AND } (\log_g \frac{d_1}{b_1} = \log_h\frac{d_2}{b_2}) \\
|
||||
\text{OR}\\
|
||||
(\log_g \frac{d_1}{a_1} = \log_h\frac{d_2}{a_2}) \text{ AND } (\log_g \frac{c_1}{b_1} = \log_h\frac{c_2}{b_2})
|
||||
$$
|
||||
|
||||
The firstMessage and finalMessage fields are generated using the sigma-protocol disjunction composition of the sigma protocols for the two conjuction statements, and those in turn are generated using the sigma-protocol conjunction statement of the basic Schnorr proofs (more details in the [protobuf file](mixing.proto)).
|
||||
|
||||
### Location
|
||||
The location field gives the layer number (column) and switchIdx (index within the column) for the 2x2 switch which this proof references. The input ciphertexts to switch $s$ in layer $i$ are in positions $2s$, $2s+1$ in column $i$ of the ciphertext matrix. The indices of the output ciphertexts in column $i+1$ are given in the location field (out0 is the index of the first output ciphertext and out1 the second).
|
||||
|
||||
### Integers
|
||||
Integers are serialized using the [BigInteger](crypto.proto) protobuf message, whose data field contains the integer encoded as in Java's [BigInteger.toByteArray()](http://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#toByteArray()) method.
|
||||
|
||||
|
||||
### Fiat-Shamir "Random Oracle"
|
||||
The Fiat-Shamir heuristic uses a "random oracle". We use the following java code as the implementation of the oracle.
|
||||
|
||||
|
||||
public BigInteger hash(byte[] input) {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.reset();
|
||||
|
||||
byte[] digest = md.digest(input);
|
||||
return new BigInteger(1,digest);
|
||||
}
|
||||
|
||||
Note that our Sigma-protocols use Integers as a challenge, so the random oracle returns a BigInteger. The input to the oracle is always a protobuf Message; we convert it to a byte array using its toByteArray() method.
|
||||
|
||||
## The Mixer Command-line Utility
|
||||
The Mixer application can generate keys, encrypt, mix, verify and decrypt. The jar file can be run using "java -jar mixer.jar"
|
||||
|
||||
Run
|
||||
|
||||
java -jar mixer.jar -h
|
||||
|
||||
To get a summary of command line options.
|
||||
### Examples
|
||||
|
||||
#### Generate a new Key-Pair
|
||||
|
||||
java -jar mixer.jar -g -k ecelgamal.key
|
||||
|
||||
Generates the keys in the file ecelgamal.key
|
||||
|
||||
#### Encrypt some plaintexts
|
||||
(run after generating keys)
|
||||
|
||||
java -jar mixer.jar -k ecelgamal.key -e -i infile.txt -o outfile.enc
|
||||
|
||||
**infile.txt** should consist of multiple lines; each line is used as a plaintext. If you get a warning message about inputs being truncated, you must ensure the longest line is shorter than about 20 chars (each plaintext must fit into a single group element, and there is some extra protobuf overhead)
|
||||
|
||||
**outfile.enc** will contain a 0-layer mixnet (i.e., a single column of ciphertexts). The plaintexts will be padded with empty lines to the nearest power of two.
|
||||
|
||||
#### Run the mix network
|
||||
(run after encrypting some plaintexts)
|
||||
|
||||
java -jar mixer.jar -k ecelgamal.key -i outfile.enc -o mixed.enc
|
||||
|
||||
**mixed.enc** will contain the mixnet output including proofs.
|
||||
|
||||
#### Verify the mix
|
||||
|
||||
java -jar mixer.jar -k ecelgamal.key -i mixed.enc
|
||||
|
||||
This doesn't write output. You can add the "-s" flag for strict verification; strict verification
|
||||
checks that the Benes network structure matches our implementation exactly (otherwise
|
||||
the verifier just ensures that the output is a permutation of the input).
|
||||
|
||||
#### Decrypt the output
|
||||
|
||||
java -jar mixer.jar -k ecelgamal.key -d -i mixed.enc -o decrypted.txt
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
../src/main/proto/meerkat/mixing.proto
|
|
@ -0,0 +1 @@
|
|||
../gradlew
|
|
@ -1,29 +1,30 @@
|
|||
package meerkat.mixer.mixing;
|
||||
package meerkat.mixer;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.Encryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.mixer.network.BenesNetwork;
|
||||
import meerkat.mixer.network.PermutationNetwork;
|
||||
import meerkat.mixer.network.RandomPermutation;
|
||||
import meerkat.mixer.proofs.Mix2nizk;
|
||||
import meerkat.protobuf.Crypto.EncryptionRandomness;
|
||||
import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage;
|
||||
import meerkat.protobuf.Mixing.ZeroKnowledgeProof;
|
||||
import meerkat.protobuf.Mixing.Mix2Proof;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* an implementation of meerkat.crypto.mixnet.Mixer
|
||||
* meerkat.mixer.mixing algorithm on set of n encrypted votes:
|
||||
* 0. asset n is power of two
|
||||
* 1. set switches according to benes network on random permutation
|
||||
* Run Abe's permutation network mixing algorithm on set of n encrypted votes:
|
||||
* 0. n is power of two
|
||||
* 1. set switches according to Benes network on random permutation
|
||||
* 2. re encrypt and mix with respect to switches values (encryptor.rerandomize)
|
||||
* 3. generate zero knowledge proof on each re encrypted couple
|
||||
* 4. return proofs table + encryption table
|
||||
*
|
||||
*/
|
||||
public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
||||
public class MixGenerator {
|
||||
|
||||
private final Mix2ZeroKnowledgeProver prover;
|
||||
private final Mix2nizk.Prover prover;
|
||||
private final Encryption encryptor;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +32,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
|||
* @param prover
|
||||
* @param encryptor
|
||||
*/
|
||||
public Mixer(Mix2ZeroKnowledgeProver prover, Encryption encryptor) {
|
||||
public MixGenerator(Mix2nizk.Prover prover, Encryption encryptor) {
|
||||
this.prover = prover;
|
||||
this.encryptor = encryptor;
|
||||
}
|
||||
|
@ -80,89 +81,92 @@ 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
|
||||
,EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||
Switch[] switchesLayer;
|
||||
int index1,index2;
|
||||
RerandomizableEncryptedMessage e1,e2;
|
||||
private void rerandomize(PermutationNetwork mixNetwork,
|
||||
RerandomizableEncryptedMessage[][] encryptionTable,
|
||||
EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||
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 ZeroKnowledgeProof[][] generateZeroKnowledgeProofTable(int n, int layers, MixNetwork mixNetwork
|
||||
private Mix2Proof[][] generateMix2ProofTable(PermutationNetwork mixNetwork
|
||||
, RerandomizableEncryptedMessage[][] encryptionTable
|
||||
, EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException {
|
||||
Switch[] switchesLayer;
|
||||
int index1,index2;
|
||||
int switchIndex = 0;
|
||||
int nDiv2 = n >> 1;
|
||||
ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2];
|
||||
int layers = mixNetwork.getNumLayers();
|
||||
int n = mixNetwork.getNumInputs();
|
||||
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);
|
||||
|
||||
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);
|
||||
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];
|
||||
|
||||
switchIndex = (switchIndex + 1) % nDiv2;
|
||||
proofsTable[layer][switchIdx] =
|
||||
prover.prove(a, b, c, d, isCrossed, layer, switchIdx, out0, out1, r1, r2);
|
||||
}
|
||||
}
|
||||
return proofsTable;
|
||||
|
@ -172,7 +176,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer {
|
|||
* mix given encrypted votes using random
|
||||
* @param ciphertexts encrypted votes
|
||||
* @param random
|
||||
* @return meerkat.mixer.mixing result
|
||||
* @return meerkat.mixProverVerifier.network result
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public MixerOutput mix(List<RerandomizableEncryptedMessage> ciphertexts,Random random) throws InvalidProtocolBufferException {
|
||||
|
@ -180,14 +184,17 @@ 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));
|
||||
|
||||
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);
|
||||
ZeroKnowledgeProof[][] proofsTable = generateZeroKnowledgeProofTable(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.MixerOutput(logN, proofsTable, encryptionTable);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package meerkat.mixer;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.mixer.network.BenesNetwork;
|
||||
import meerkat.mixer.network.PermutationNetwork;
|
||||
import meerkat.mixer.proofs.Mix2nizk;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/30/2015.
|
||||
* provide one operation - verify meerkat.mixProverVerifier.network output
|
||||
*/
|
||||
public final class MixVerifier {
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger(MixVerifier.class);
|
||||
/**
|
||||
* constructor
|
||||
* @param verifier
|
||||
* @param mixerOutput
|
||||
* @param strict if true, check that the network structure matches our implementation of the Benes network exactly.
|
||||
* if false, only checks that the result is a permutation.
|
||||
* @return true iff the meerkat.mixProverVerifier.network output is valid
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public static boolean verifyTable(Mix2nizk.Verifier verifier, MixerOutput mixerOutput, boolean strict)
|
||||
throws InvalidProtocolBufferException {
|
||||
|
||||
PermutationNetwork net = null;
|
||||
|
||||
int layers = mixerOutput.getNumLayers();
|
||||
int n = 1 << mixerOutput.getLogN();
|
||||
|
||||
if (strict) {
|
||||
net = new BenesNetwork(mixerOutput.getLogN());
|
||||
}
|
||||
|
||||
//initialize outputUsed table
|
||||
// used to check BeneshNet validity
|
||||
boolean[][] outputUsed = new boolean[layers][n];
|
||||
for (boolean[] outputUsedLayer: outputUsed) {
|
||||
Arrays.fill(outputUsedLayer,false);
|
||||
}
|
||||
|
||||
boolean[][] switchUsed = new boolean[layers][n / 2];
|
||||
for (boolean[] switchUsedLayer: switchUsed) {
|
||||
Arrays.fill(switchUsedLayer,false);
|
||||
}
|
||||
|
||||
Mixing.Mix2Proof[][] Mix2Proofs = mixerOutput.getProofs();
|
||||
Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages();
|
||||
|
||||
for (int i = 0; i < Mix2Proofs.length ; i++){
|
||||
for (int j = 0; j < Mix2Proofs[i].length ; j ++){
|
||||
int out0,out1,layer, switchIdx;
|
||||
|
||||
Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
|
||||
Mixing.Mix2Proof.Location location = zkp.getLocation();
|
||||
out0 = location.getOut0();
|
||||
out1 = location.getOut1();
|
||||
layer = location.getLayer();
|
||||
switchIdx = location.getSwitchIdx();
|
||||
|
||||
if (strict) {
|
||||
// Check that location is correct
|
||||
int expectedOut0 = net.getInputIdxInNextLayer(layer, 2 * switchIdx);
|
||||
if (out0 != expectedOut0) {
|
||||
logger.error("Input {} in layer {} goes to {} instead of {}", 2 * switchIdx, layer, out0, expectedOut0);
|
||||
return false;
|
||||
}
|
||||
int expectedOut1 = net.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
|
||||
if (out0 != expectedOut0) {
|
||||
logger.error("Input {} in layer {} goes to {} instead of {}", 2 * switchIdx + 1, layer, out1, expectedOut1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// mark location in table
|
||||
if (switchUsed[layer][switchIdx]) {
|
||||
logger.error("Switch {} in layer {} used twice!", switchIdx, layer);
|
||||
return false;
|
||||
}
|
||||
switchUsed[layer][switchIdx] = true;
|
||||
|
||||
if (outputUsed[layer][out0]) {
|
||||
logger.error("Output {} in layer {} used twice!", out0, layer);
|
||||
return false;
|
||||
}
|
||||
outputUsed[layer][out0] = true;
|
||||
|
||||
if (outputUsed[layer][out1]) {
|
||||
logger.error("Output {} in layer {} used twice!", out1, layer);
|
||||
return false;
|
||||
}
|
||||
outputUsed[layer][out1] = true;
|
||||
|
||||
// verify proof
|
||||
if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx],
|
||||
rerandomizableEncryptedMessages[layer][2 * switchIdx + 1],
|
||||
rerandomizableEncryptedMessages[layer + 1][out0],
|
||||
rerandomizableEncryptedMessages[layer + 1][out1],
|
||||
zkp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify all meerkat.mixProverVerifier.necessary locations for BenesNet were proved
|
||||
for (int layer = 0; layer < layers; ++layer) {
|
||||
for (int switchIdx = 0; switchIdx < n / 2; ++switchIdx) {
|
||||
if (!switchUsed[layer][switchIdx]) {
|
||||
logger.error("Switch {} in layer {} was not used!", switchIdx, layer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < n / 2; ++i) {
|
||||
if (!outputUsed[layer][i]) {
|
||||
logger.error("Output {} in layer {} was not used!", i, layer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package meerkat.mixer;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/18/2016.
|
||||
* container for meerkat.mixProverVerifier.network.mix result.
|
||||
*/
|
||||
public class MixerOutput {
|
||||
private final Mixing.Mix2Proof[][] proofs;
|
||||
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
|
||||
private final int logN;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @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.
|
||||
* We allow null proofs as a special case -- this is used to store the input to the
|
||||
* first mixProverVerifier (as a 0-layer mix).
|
||||
*/
|
||||
public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs,
|
||||
Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
|
||||
this.proofs = proofs;
|
||||
this.encryptedMessages = encryptedMessages;
|
||||
this.logN = logN;
|
||||
}
|
||||
|
||||
public Mixing.Mix2Proof[][] getProofs() {
|
||||
return proofs;
|
||||
}
|
||||
|
||||
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() {
|
||||
return encryptedMessages;
|
||||
}
|
||||
|
||||
public int getLogN() {
|
||||
return logN;
|
||||
}
|
||||
|
||||
public int getNumLayers() {
|
||||
return proofs == null ? 0 : proofs.length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from an InputStream. The data should have been written by {@link #writeDelimitedTo(OutputStream)}
|
||||
* @param in
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static MixerOutput parseDelimitedFrom(InputStream in) throws IOException {
|
||||
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseDelimitedFrom(in);
|
||||
int n = 1 << header.getLogN();
|
||||
int layers = header.getLayers();
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage[][] encryptedMessages = new Crypto.RerandomizableEncryptedMessage[layers + 1][n];
|
||||
Mixing.Mix2Proof[][] proofs = null;
|
||||
if (layers > 0)
|
||||
proofs = new Mixing.Mix2Proof[header.getLayers()][n / 2];
|
||||
|
||||
for (int i = 0; i < encryptedMessages.length; ++i) {
|
||||
for (int j = 0; j < encryptedMessages[i].length; ++j) {
|
||||
encryptedMessages[i][j] = Crypto.RerandomizableEncryptedMessage.parseDelimitedFrom(in);
|
||||
}
|
||||
}
|
||||
if (layers > 0) {
|
||||
for (int i = 0; i < proofs.length; ++i) {
|
||||
for (int j = 0; j < proofs[i].length; ++j) {
|
||||
proofs[i][j] = Mixing.Mix2Proof.parseDelimitedFrom(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new MixerOutput(header.getLogN(), proofs, encryptedMessages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to an outputstream.
|
||||
* This format can be parsed by {@link #parseDelimitedFrom(InputStream)}
|
||||
* @param out
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeDelimitedTo(OutputStream out) throws IOException {
|
||||
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.newBuilder()
|
||||
.setLogN(getLogN())
|
||||
.setLayers(getNumLayers())
|
||||
.build();
|
||||
header.writeDelimitedTo(out);
|
||||
|
||||
for (int i = 0; i < encryptedMessages.length; ++i) {
|
||||
for (int j = 0; j < encryptedMessages[i].length; ++j) {
|
||||
encryptedMessages[i][j].writeDelimitedTo(out);
|
||||
}
|
||||
}
|
||||
if (proofs != null) {
|
||||
for (int i = 0; i < proofs.length; ++i) {
|
||||
for (int j = 0; j < proofs[i].length; ++j) {
|
||||
proofs[i][j].writeDelimitedTo(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +1,38 @@
|
|||
package meerkat.mixer.main;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.mixer.MixerOutput;
|
||||
import meerkat.protobuf.BulletinBoardAPI;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/17/2015.
|
||||
* provide convert operation from batch data to meerkat.mixer.mixing output and backwards
|
||||
* provide convert operation from batch data to meerkat.mixProverVerifier.network 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
|
||||
* convert meerkat.mixProverVerifier.network output to batch data
|
||||
* @param mixerOutput
|
||||
* @return meerkat.mixer.mixing output as list of batch data
|
||||
* @return meerkat.mixProverVerifier.network output as list of batch data
|
||||
*/
|
||||
public List<BulletinBoardAPI.BatchChunk> MixerOutput2BatchChunk(MixerOutput mixerOutput) {
|
||||
|
||||
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.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) {
|
||||
for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) {
|
||||
for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) {
|
||||
for (Mixing.Mix2Proof zkp : zkpLayer) {
|
||||
result.add(BulletinBoardAPI.BatchChunk.newBuilder()
|
||||
.setData(zkp.toByteString())
|
||||
.build());
|
||||
|
@ -77,7 +49,7 @@ public class BatchConverter {
|
|||
}
|
||||
|
||||
/**
|
||||
* convert batch data list to meerkat.mixer.mixing output
|
||||
* convert batch data list to meerkat.mixProverVerifier.network output
|
||||
* @param batchChunkList
|
||||
* @return batch data list as MixerOutput
|
||||
* @throws Exception
|
||||
|
@ -85,17 +57,18 @@ 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.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2];
|
||||
Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2];
|
||||
for (int layer = 0; layer < layers; layer++)
|
||||
{
|
||||
for (int proofIndex = 0 ; proofIndex < nDiv2 ; proofIndex ++)
|
||||
{
|
||||
proofs[layer][proofIndex] = Mixing.ZeroKnowledgeProof.parseFrom(batchChunkList.remove(0).getData());
|
||||
proofs[layer][proofIndex] = Mixing.Mix2Proof.parseFrom(batchChunkList.remove(0).getData());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +83,7 @@ public class BatchConverter {
|
|||
}
|
||||
}
|
||||
|
||||
return new meerkat.mixer.mixing.MixerOutput(n,layers,proofs,encryptions);
|
||||
return new meerkat.mixer.MixerOutput(logN, proofs,encryptions);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package meerkat.mixer.main;
|
||||
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.mixer.MixerOutput;
|
||||
import meerkat.mixer.proofs.Mix2nizk;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.mixer.necessary.AsyncBulletinBoardClient;
|
||||
import meerkat.mixer.necessary.CompleteBatch;
|
||||
import meerkat.mixer.verifier.VerifyTable;
|
||||
import meerkat.mixer.MixVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/17/2015.
|
||||
* implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch>
|
||||
*/
|
||||
* Handles callback for receiving a complete mix proof table from the bulletin board.
|
||||
*/
|
||||
public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch> {
|
||||
|
||||
private MixerOutput mixerOutput;
|
||||
|
@ -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;
|
||||
private final Mix2nizk.Verifier verifier;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n
|
||||
* @param layers
|
||||
* @param verifier
|
||||
*/
|
||||
public BatchHandler(int n, int layers, Mix2ZeroKnowledgeVerifier verifier) {
|
||||
public BatchHandler(Mix2nizk.Verifier verifier) {
|
||||
this.mixerOutput = null;
|
||||
this.n = n;
|
||||
this.layers = layers;
|
||||
this.msgReceived = false;
|
||||
this.t = null;
|
||||
this.verifier = verifier;
|
||||
|
@ -66,39 +61,39 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
|
|||
}
|
||||
|
||||
/**
|
||||
* convert batch data to meerkat.mixer.mixing output
|
||||
* convert batch data to meerkat.mixProverVerifier.network output
|
||||
* @throws Exception
|
||||
*/
|
||||
private void convertMessage() throws Exception {
|
||||
BatchConverter batchConverter = new BatchConverter(n,layers);
|
||||
BatchConverter batchConverter = new BatchConverter();
|
||||
this.mixerOutput = batchConverter.BatchChunkList2MixerOutput(msg.getBatchChunkList());
|
||||
}
|
||||
|
||||
/**
|
||||
* call convert message, and if succeed verify the table
|
||||
* @return return true iff the given batch message is valid meerkat.mixer.mixing output
|
||||
* @return return true iff the given batch message is valid meerkat.mixProverVerifier.network output
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean verifyTable() throws Exception {
|
||||
public boolean verifyTable(boolean strict) throws Exception {
|
||||
if (mixerOutput == null) {
|
||||
convertMessage();
|
||||
}
|
||||
return VerifyTable.verifyTable(verifier, n, mixerOutput);
|
||||
return MixVerifier.verifyTable(verifier, mixerOutput, strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* extract input for meerkat.mixer.mixing from previous mixers output
|
||||
* extract input for meerkat.mixProverVerifier.network from previous mixers output
|
||||
* @return last layer of encrypted votes as list
|
||||
* @throws Throwable in case if failure
|
||||
*/
|
||||
public List<Crypto.RerandomizableEncryptedMessage> getInputForMixer() throws Throwable {
|
||||
public List<Crypto.RerandomizableEncryptedMessage> getInputForMixer(boolean strictVerification) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
if(!verifyTable()){
|
||||
throw new Exception("in valid table");
|
||||
if(!verifyTable(strictVerification)){
|
||||
throw new Exception("invalid table");
|
||||
}
|
||||
return Arrays.asList(mixerOutput.getEncryptedMessages()[layers]);//there are layers + 1
|
||||
return Arrays.asList(mixerOutput.getEncryptedMessages()[mixerOutput.getNumLayers()]); //there are layers + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package meerkat.mixer.main;
|
||||
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.crypto.mixnet.Mixer;
|
||||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.mixer.MixGenerator;
|
||||
import meerkat.mixer.MixerOutput;
|
||||
import meerkat.mixer.proofs.Mix2nizk;
|
||||
import meerkat.protobuf.BulletinBoardAPI;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.mixer.mixing.MixNetwork;
|
||||
import meerkat.mixer.necessary.AsyncBulletinBoardClient;
|
||||
|
||||
|
||||
|
@ -16,17 +15,16 @@ import java.util.Random;
|
|||
|
||||
/**
|
||||
* Created by Tzlil on 12/17/2015.
|
||||
* this class define all the operation meerkat.mixer.mixing party should do:
|
||||
* this class define all the operation meerkat.mixProverVerifier.network party should do:
|
||||
* 1. receive previous mixers output (re encrypted votes + proofs)
|
||||
* 2. verify its input
|
||||
* 3. mix
|
||||
* 4. send the meerkat.mixer.mixing output
|
||||
* 4. send the meerkat.mixProverVerifier.network output
|
||||
*/
|
||||
public class MainMixing {
|
||||
|
||||
private final Mixer mixer;
|
||||
private final Mix2ZeroKnowledgeVerifier verifier;
|
||||
private final int n, layers;
|
||||
private final MixGenerator mixer;
|
||||
private final Mix2nizk.Verifier verifier;
|
||||
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(MixGenerator mixer, Mix2nizk.Verifier 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;
|
||||
}
|
||||
|
@ -57,14 +52,14 @@ public class MainMixing {
|
|||
* @param callback
|
||||
* @throws Throwable
|
||||
*/
|
||||
public void main(List<Integer> prevBatchIds, int batchId, Random random, AsyncBulletinBoardClient.ClientCallback<?> callback) throws Throwable {
|
||||
public void main(List<Integer> prevBatchIds, int batchId, boolean strictVerification, Random random, AsyncBulletinBoardClient.ClientCallback<?> callback) throws Throwable {
|
||||
|
||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput;
|
||||
|
||||
List<BatchHandler> batchHandlers = new ArrayList<BatchHandler>(prevBatchIds.size());
|
||||
BatchHandler currentBatchHandler;
|
||||
for (Integer prevBatchId : prevBatchIds) {
|
||||
currentBatchHandler = new BatchHandler(n, layers,verifier);
|
||||
currentBatchHandler = new BatchHandler(verifier);
|
||||
asyncBulletinBoardClient.readBatch(id, prevBatchId,currentBatchHandler);
|
||||
batchHandlers.add(currentBatchHandler);
|
||||
}
|
||||
|
@ -77,13 +72,13 @@ public class MainMixing {
|
|||
}
|
||||
// assert all handlers succeeded
|
||||
for (BatchHandler batchHandler : batchHandlers) {
|
||||
if(!batchHandler.verifyTable()){
|
||||
if(!batchHandler.verifyTable(strictVerification)){
|
||||
throw new Exception("invalid input");
|
||||
}
|
||||
}
|
||||
|
||||
BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1);
|
||||
mixerInput = lastBatchHandler.getInputForMixer();
|
||||
mixerInput = lastBatchHandler.getInputForMixer(strictVerification);
|
||||
|
||||
MixerOutput mixerOutput = mixer.mix(mixerInput,random);
|
||||
updateBB(mixerOutput, batchId, callback);
|
||||
|
@ -91,7 +86,7 @@ public class MainMixing {
|
|||
}
|
||||
|
||||
/**
|
||||
* send meerkat.mixer.mixing output to BB
|
||||
* send meerkat.mixProverVerifier.network output to BB
|
||||
* @param mixerOutput
|
||||
* @param batchId
|
||||
* @param callback
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
package meerkat.mixer.main;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.StringValue;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.MixGenerator;
|
||||
import meerkat.mixer.MixVerifier;
|
||||
import meerkat.mixer.MixerOutput;
|
||||
import meerkat.mixer.proofs.concrete.Mix2nizk;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.lang.System.exit;
|
||||
|
||||
/**
|
||||
* Command-line mixProverVerifier and verifier.
|
||||
*/
|
||||
public class Mix {
|
||||
final static String DEFAULT_ECGROUP = "secp256k1";
|
||||
final static Logger logger = LoggerFactory.getLogger(Mix.class);
|
||||
|
||||
public Random rand;
|
||||
public ECGroup group;
|
||||
public ECElGamalEncryption enc;
|
||||
public ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
public ECElGamal.SK secretKey;
|
||||
public Mix2nizk mixProverVerifier;
|
||||
|
||||
public MixerOutput inMix;
|
||||
|
||||
public Mix() {
|
||||
rand = new SecureRandom();
|
||||
enc = new ECElGamalEncryption();
|
||||
serializedPk = null;
|
||||
secretKey = null;
|
||||
}
|
||||
|
||||
public void loadMix(File inFile) throws IOException {
|
||||
|
||||
assert(serializedPk != null);
|
||||
InputStream in = new FileInputStream(inFile);
|
||||
inMix = MixerOutput.parseDelimitedFrom(in);
|
||||
in.close();
|
||||
logger.info("Loaded mixnet with {} layers and logN={}", inMix.getNumLayers(), inMix.getLogN());
|
||||
}
|
||||
|
||||
public boolean verify(boolean strict) {
|
||||
try {
|
||||
logger.info("Starting verification of {} ciphertexts", 1 << inMix.getLogN());
|
||||
long startTime = System.currentTimeMillis();
|
||||
boolean ok = MixVerifier.verifyTable(mixProverVerifier, inMix, strict);
|
||||
long endTime = System.currentTimeMillis();
|
||||
logger.info("Verification took {} seconds", (endTime - startTime) / 1000f);
|
||||
return ok;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
logger.error("Badly formatted encryptions", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void mix(File outFile) throws IOException {
|
||||
MixGenerator mixer = new MixGenerator(mixProverVerifier, enc);
|
||||
|
||||
List<Crypto.RerandomizableEncryptedMessage> encryptedMessages = Arrays.asList(inMix.getEncryptedMessages()[inMix.getNumLayers()]);
|
||||
|
||||
logger.info("Starting mix of {} ciphertexts", encryptedMessages.size());
|
||||
long startTime = System.currentTimeMillis();
|
||||
MixerOutput outMix = mixer.mix(encryptedMessages, rand);
|
||||
long endTime = System.currentTimeMillis();
|
||||
logger.info("Mix done (took {} seconds)", (endTime - startTime) / 1000f);
|
||||
|
||||
OutputStream out = new FileOutputStream(outFile);
|
||||
outMix.writeDelimitedTo(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
// For testing purposes
|
||||
|
||||
public void setPK(ConcreteCrypto.ElGamalPublicKey serializedPk) {
|
||||
this.serializedPk = serializedPk;
|
||||
|
||||
try {
|
||||
enc.init(serializedPk);
|
||||
group = enc.getGroup();
|
||||
} catch (InvalidKeySpecException e) {
|
||||
logger.error("Invalid EC-ElGamal public key", e);
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
mixProverVerifier = new Mix2nizk(rand, enc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECElGamal key pair and write it serialized to file.
|
||||
*
|
||||
* @param outFile
|
||||
*/
|
||||
public void createKeypair(File outFile) throws IOException {
|
||||
group = new ECGroup(DEFAULT_ECGROUP);
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
secretKey = new ECElGamal.SK(group, sk);
|
||||
|
||||
serializedPk = Util.encodePK(group, secretKey);
|
||||
setPK(serializedPk);
|
||||
Crypto.BigInteger serializedSk = Util.encodeBigInteger(sk);
|
||||
|
||||
OutputStream out = new FileOutputStream(outFile);
|
||||
|
||||
serializedPk.writeDelimitedTo(out);
|
||||
serializedSk.writeDelimitedTo(out);
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a public key and optionally a secret key from a file.
|
||||
* @param inFile
|
||||
* @throws IOException
|
||||
* @throws InvalidKeySpecException
|
||||
*/
|
||||
public void loadKeypair(File inFile) throws IOException, InvalidKeySpecException {
|
||||
InputStream in = new FileInputStream(inFile);
|
||||
serializedPk = ConcreteCrypto.ElGamalPublicKey.parseDelimitedFrom(in);
|
||||
|
||||
setPK(serializedPk);
|
||||
|
||||
try {
|
||||
Crypto.BigInteger serializedSk = Crypto.BigInteger.parseDelimitedFrom(in);
|
||||
secretKey = Util.decodeSK(serializedPk, serializedSk);
|
||||
} catch (EOFException e) {
|
||||
logger.debug("File {} does not have a secret key", inFile);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt the output of a mixnet
|
||||
* Outputs to a file, one line per decoded element.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void decrypt(File outFile) throws IOException {
|
||||
PrintStream out = new PrintStream(outFile);
|
||||
|
||||
assert(inMix != null);
|
||||
assert(inMix.getEncryptedMessages() != null);
|
||||
|
||||
logger.info("Decrypting {} ciphertexts", inMix.getEncryptedMessages()[inMix.getNumLayers()].length);
|
||||
for (Crypto.RerandomizableEncryptedMessage ciphertext : inMix.getEncryptedMessages()[inMix.getNumLayers()]) {
|
||||
StringValue plaintext = Util.decrypt(StringValue.class, secretKey, group, ciphertext);
|
||||
out.println(plaintext.getValue());
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void encrypt(File inFile, File outFile) throws IOException {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
|
||||
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
in.close();
|
||||
|
||||
int n = lines.size();
|
||||
int logN = 32 - Integer.numberOfLeadingZeros(n - 1);
|
||||
n = 1 << logN; // We need the smallest power of 2 greater than the size
|
||||
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage ciphers[][] = new Crypto.RerandomizableEncryptedMessage[1][n];
|
||||
|
||||
logger.info("Encrypting {} plaintexts (padded to {})", lines.size(), n);
|
||||
for (int i = 0; i < lines.size(); ++i) {
|
||||
ciphers[0][i] = enc.encrypt(StringValue.newBuilder().setValue(lines.get(i)).build(), enc.generateRandomness(rand));
|
||||
}
|
||||
|
||||
// Pad with empty values
|
||||
StringValue empty = StringValue.newBuilder().setValue("").build();
|
||||
for (int i = lines.size(); i < n; ++i) {
|
||||
ciphers[0][i] = enc.encrypt(empty, enc.generateRandomness(rand));
|
||||
}
|
||||
|
||||
inMix = new MixerOutput(logN, null, ciphers);
|
||||
|
||||
OutputStream out = new FileOutputStream(outFile);
|
||||
inMix.writeDelimitedTo(out);
|
||||
out.close();
|
||||
logger.info("Wrote mixnet with {} layers and logN={}", inMix.getNumLayers(), inMix.getLogN());
|
||||
}
|
||||
|
||||
|
||||
static void printHelp(OptionParser parser) {
|
||||
printHelp(null, parser);
|
||||
}
|
||||
|
||||
static void printHelp(String msg, OptionParser parser) {
|
||||
if (msg != null)
|
||||
System.out.println(msg);
|
||||
try {
|
||||
parser.printHelpOn(System.out);
|
||||
} catch (IOException e) {
|
||||
// should never happen
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
OptionParser parser = new OptionParser();
|
||||
final OptionSpec<Void> OPT_HELP = parser.accepts("help", "Print help");
|
||||
final OptionSpec<Void> OPT_GENKEY = parser.accepts("genkey", "Generate a key-pair (write into key file)");
|
||||
final OptionSpec<Void> OPT_DECRYPT = parser.accepts("decrypt", "Decrypt using given keypair");
|
||||
final OptionSpec<File> OPT_KEYFILE = parser.accepts("keys", "File containing public key (or keypair for decryption)").withRequiredArg().ofType(File.class);
|
||||
final OptionSpec<Void> OPT_ENCRYPT = parser.accepts("encrypt", "Decrypt using given keypair");
|
||||
final OptionSpec<Void> OPT_STRICT = parser.accepts("strict", "Use strict verification (verify that network matches our Benes implementation)");
|
||||
final OptionSpec<File> OPT_INPUTFILE = parser.accepts("infile", "Input file (if mixing, should contain ciphertext or mixProverVerifier output; if verifying, mixProverVerifier output)").withRequiredArg().ofType(File.class);
|
||||
final OptionSpec<File> OPT_OUTPUTFILE = parser.accepts("outfile", "Output file. If given, operate in Mix mode; otherwise in verify mode.").withRequiredArg().ofType(File.class);
|
||||
|
||||
OptionSet options = parser.parse(args);
|
||||
if (options.has(OPT_HELP)) {
|
||||
printHelp(parser);
|
||||
return;
|
||||
}
|
||||
|
||||
File keyFile = options.valueOf(OPT_KEYFILE);
|
||||
if (keyFile == null) {
|
||||
printHelp("Must specify key file", parser);
|
||||
return;
|
||||
}
|
||||
|
||||
File inFile = options.valueOf(OPT_INPUTFILE);
|
||||
if ((inFile == null || !inFile.canRead()) && !options.has(OPT_GENKEY)) {
|
||||
printHelp("Must specify input file except for key generation" + (inFile.canRead() ? "" : " (can't read inFile)"), parser);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
File outFile = options.valueOf(OPT_OUTPUTFILE);
|
||||
|
||||
Mix mix = new Mix();
|
||||
|
||||
try {
|
||||
if (options.has(OPT_GENKEY)) {
|
||||
mix.createKeypair(keyFile);
|
||||
} else {
|
||||
mix.loadKeypair(keyFile);
|
||||
if (options.has(OPT_ENCRYPT)) {
|
||||
mix.encrypt(inFile, outFile);
|
||||
} else if (options.has(OPT_DECRYPT)) {
|
||||
mix.loadMix(inFile);
|
||||
mix.decrypt(outFile);
|
||||
} else if (options.has(OPT_OUTPUTFILE)) {
|
||||
// Mix mode
|
||||
mix.loadMix(inFile);
|
||||
mix.mix(outFile);
|
||||
} else {
|
||||
mix.loadMix(inFile);
|
||||
boolean ok = mix.verify(options.has(OPT_STRICT));
|
||||
if (ok) {
|
||||
logger.info("Verification successful");
|
||||
} else {
|
||||
logger.error("Verification failed!");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeySpecException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
package meerkat.mixer.mixing;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/18/2016.
|
||||
* implements meerkat.crypto.mixnet.MixerOutput interface
|
||||
* container for meerkat.mixer.mixing.mix result.
|
||||
*/
|
||||
public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{
|
||||
private final Mixing.ZeroKnowledgeProof[][] proofs;
|
||||
private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages;
|
||||
private final int n;
|
||||
private final int layers;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n number of votes
|
||||
* @param layers
|
||||
* @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.ZeroKnowledgeProof[][] proofs
|
||||
, Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
|
||||
this.proofs = proofs;
|
||||
this.encryptedMessages = encryptedMessages;
|
||||
this.n = n;
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Mixing.ZeroKnowledgeProof[][] getProofs() {
|
||||
return proofs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages() {
|
||||
return encryptedMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getN() {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* print the output, encrypted messages and proofs, to folder
|
||||
* @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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create new file contains single proof
|
||||
* @param proofsDir
|
||||
* @param proof
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException {
|
||||
Mixing.ZeroKnowledgeProof.Location location = proof.getLocation();
|
||||
int layer = location.getLayer();
|
||||
int i = location.getI();
|
||||
int j = location.getJ();
|
||||
String fileName = proofsDir+"/layer" + layer +"/" + i +"_" + j;
|
||||
|
||||
File file = new File(fileName);
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(proof.toByteArray());
|
||||
fos.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* create new file contains single encrypted message
|
||||
* @param encDir
|
||||
* @param layer
|
||||
* @param i
|
||||
* @param enc
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeEncToFile(String encDir,int layer,int i, Crypto.RerandomizableEncryptedMessage enc) throws IOException {
|
||||
|
||||
String fileName;
|
||||
if(layer >= 0)
|
||||
fileName = encDir+"/layer" + layer +"/" + i;
|
||||
else
|
||||
fileName = encDir+"/input/" + i;
|
||||
|
||||
File file = new File(fileName);
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(enc.toByteArray());
|
||||
fos.close();
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package meerkat.mixer.mixing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/17/2015.
|
||||
* container for random permutation
|
||||
* the permutation is sated in constructor and can't be change
|
||||
*/
|
||||
public class RandomPermutation {
|
||||
public final int[] permutation;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n permutation size
|
||||
* @param random
|
||||
*/
|
||||
public RandomPermutation(int n,Random random) {
|
||||
this.permutation = generatePermutation(n,random);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate random permutation ovver [0,n)
|
||||
* @param n permutation size
|
||||
* @param random
|
||||
* @return permutation
|
||||
*/
|
||||
private int[] generatePermutation(int n,Random random){
|
||||
List<Integer> numbers= new ArrayList<Integer>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
numbers.add(i);
|
||||
}
|
||||
|
||||
int[] result = new int[n];
|
||||
int index;
|
||||
for (int i = 0; i < n; i++) {
|
||||
index = random.nextInt(n - i);
|
||||
result[i] = numbers.get(index);
|
||||
numbers.remove(index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package meerkat.mixer.mixing;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/15/2015.
|
||||
* container for switch
|
||||
*/
|
||||
public class Switch{
|
||||
|
||||
public final int i, j, layer;
|
||||
public final boolean value;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param i
|
||||
* @param j
|
||||
* @param layer
|
||||
* @param value the switch is on or off
|
||||
*/
|
||||
public Switch(int i, int j, int layer, boolean value) {
|
||||
this.i = i;
|
||||
this.j = j;
|
||||
this.layer = layer;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Switch{" +
|
||||
"i=" + i +
|
||||
", j=" + j +
|
||||
", layer=" + layer +
|
||||
", value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Generate the Benes Network
|
||||
*/
|
||||
public class BenesNetwork implements PermutationNetwork
|
||||
{
|
||||
/**
|
||||
* log (base 2) of number of inputs to Benes network (N = 2^{logN})
|
||||
*/
|
||||
final int logN;
|
||||
|
||||
/**
|
||||
* Values of switches set for a specific permutation.
|
||||
* switchValues[layer][switchNum] is true if the corresponding switch applies the identity permutation on its inputs.
|
||||
* layer can be in the range [0, 2*logN-1), switchNum in the range (0, 2^{logN-1}-1)
|
||||
*/
|
||||
final boolean[][] switchValues;
|
||||
|
||||
public BenesNetwork(int logN) {
|
||||
this.logN = logN;
|
||||
|
||||
switchValues = new boolean[2*logN - 1][];
|
||||
for (int i = 0; i < switchValues.length; ++i)
|
||||
switchValues[i] = new boolean[1 << (logN - 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the switch output in the previous layer that connects to a specified input in the current layer.
|
||||
* Each consecutive pair of outputs is from the same switch, and each consecutive pair of inputs goes to the same switch.
|
||||
* (that is, switch j has inputs/outputs 2j and 2j+1)
|
||||
*
|
||||
* @param logN log (base 2) of number of inputs to Benes network (N = 2^{logN})
|
||||
* @param layer current layer index. Must be between 0 and 2*logN-1 (layer -1 is the inputs and layer 2*logN-1 is the outputs)
|
||||
* @param inputIdx the input Idx for the current layer (must be between 0 and (1 << logN) - 1
|
||||
*
|
||||
* @return the requested index
|
||||
*/
|
||||
public static int getOutputIdxInPreviousLayer(int logN, int layer, int inputIdx) {
|
||||
assert (layer >= 0) && (layer <= 2*logN - 1);
|
||||
assert (inputIdx >= 0) && (inputIdx < 1 << logN);
|
||||
|
||||
if ((layer == 0) || (layer == 2*logN - 1) || (inputIdx & 1) == 0) {
|
||||
// layer 0 inputs and all even inputs
|
||||
// are connected straight "across" everywhere
|
||||
return inputIdx;
|
||||
}
|
||||
|
||||
// --- Odd inputs are connected depending on layer ---
|
||||
|
||||
int crossBit;
|
||||
if (layer < logN)
|
||||
crossBit = logN - layer;
|
||||
else
|
||||
crossBit = layer - logN + 1;
|
||||
|
||||
return inputIdx ^ (1 << crossBit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of {@link #getOutputIdxInPreviousLayer(int, int, int)}
|
||||
* @param logN
|
||||
* @param layer
|
||||
* @param outputIdx
|
||||
* @return
|
||||
*/
|
||||
public static int getInputIdxInNextLayer(int logN, int layer, int outputIdx) {
|
||||
return getOutputIdxInPreviousLayer(logN, layer + 1, outputIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInputIdxInNextLayer(int layer, int outputIdx) {
|
||||
return getInputIdxInNextLayer(logN, layer, outputIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumInputs() {
|
||||
return 1 << logN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumLayers() {
|
||||
return 2*logN - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOutputIdxInPreviousLayer(int layer, int inputIdx) {
|
||||
return getOutputIdxInPreviousLayer(logN, layer, inputIdx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find in array
|
||||
* TODO: replace with more efficient data structure if this becomes a performance bottleneck
|
||||
* @param val
|
||||
* @param arr
|
||||
* @return
|
||||
*/
|
||||
static private int find(int val, int[] arr) {
|
||||
for (int i = 0; i < arr.length; ++i) {
|
||||
if (arr[i] == val)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The recursive algorithm attributed to H. Stone by A. Waksman
|
||||
* (see pg. 161 in <a href="http://grid.cs.gsu.edu/~wkim/index_files/permutation_network.pdf">paper</a>)
|
||||
* @param permOut
|
||||
* @param level
|
||||
*/
|
||||
private void setInternalPermutation(int[] permIn, int[] permOut, int idx, int level) {
|
||||
// Make sure idx is in the the range [0, 2^{level})
|
||||
assert (idx < (1 << level));
|
||||
assert (permOut.length == (1 << (logN - level)));
|
||||
assert (permIn.length == permOut.length);
|
||||
|
||||
final int Nover2 = 1 << (logN - level - 1);
|
||||
|
||||
// Base case
|
||||
if (level == logN - 1) {
|
||||
if (permOut[0] == permIn[0])
|
||||
switchValues[level][idx] = false;
|
||||
else
|
||||
switchValues[level][idx] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int nextLen = permOut.length >>> 1;
|
||||
int[] upperPermIn = new int[nextLen];
|
||||
int[] lowerPermIn = new int[nextLen];
|
||||
|
||||
int[] upperPermOut = new int[nextLen];
|
||||
int[] lowerPermOut = new int[nextLen];
|
||||
|
||||
|
||||
SortedSet<Integer> unmatchedIndices = new TreeSet<>();
|
||||
for (int i = 0; i < permIn.length; ++i) {
|
||||
unmatchedIndices.add(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the set of switches for this level and index actually starts in switchValues
|
||||
*/
|
||||
int blockStart = idx << (logN - level - 1);
|
||||
int numSwitches = 1 << (logN - level - 1);
|
||||
|
||||
while (!unmatchedIndices.isEmpty()) {
|
||||
int i = unmatchedIndices.first();
|
||||
|
||||
do {
|
||||
//assert ((i & 1) == 0); // Algorithm guarantees only even indices are unmatched at start of loop
|
||||
unmatchedIndices.remove(i);
|
||||
unmatchedIndices.remove(i ^ 1);
|
||||
|
||||
int switchNum = i >>> 1;
|
||||
|
||||
// index of outPerm[i] after the last switch layer.
|
||||
int iSwitched;
|
||||
|
||||
if (((i & 1) == 0) && (switchNum < numSwitches / 2) || ((i & 1) == 1) && (switchNum >= numSwitches / 2)) {
|
||||
// i is in the upper half and even, or in the lower half and odd, so
|
||||
// switch must be "straight" to get i to upper half.
|
||||
switchValues[2 * logN - level - 2][blockStart + switchNum] = false;
|
||||
iSwitched = i;
|
||||
|
||||
} else {
|
||||
switchValues[2 * logN - level - 2][blockStart + switchNum] = true;
|
||||
iSwitched = i ^ 1;
|
||||
}
|
||||
|
||||
// Index of outPerm[i] in the output of the previous layer.
|
||||
int iConnectedTo = getOutputIdxInPreviousLayer(logN - level, 2 * (logN - level) - 2, iSwitched);
|
||||
int iPairConnectedTo = getOutputIdxInPreviousLayer(logN - level, 2 * (logN - level) - 2, iSwitched ^ 1);
|
||||
|
||||
upperPermOut[iConnectedTo] = permOut[i];
|
||||
lowerPermOut[iPairConnectedTo - Nover2] = permOut[i ^ 1];
|
||||
|
||||
// Index of permOut[i] before the first switch layer.
|
||||
int j = find(permOut[i], permIn);
|
||||
int jSwitchNum = j >>> 1;
|
||||
|
||||
// Index of permOut[i] after the first switch layer
|
||||
int jSwitched;
|
||||
|
||||
if ((((j & 1) == 0) && (jSwitchNum < numSwitches / 2)) || ((j & 1) == 1) && (jSwitchNum >= numSwitches / 2)) {
|
||||
// Even output in the upper half, or odd output in the lower half
|
||||
// so switch needs to be "straight" to get j to the upper half
|
||||
switchValues[level][blockStart + jSwitchNum] = false;
|
||||
jSwitched = j;
|
||||
} else {
|
||||
// Otherwise switch needs to be "crossed" to get j to upper half
|
||||
switchValues[level][blockStart + jSwitchNum] = true;
|
||||
jSwitched = j ^ 1;
|
||||
}
|
||||
|
||||
int jConnectedTo = getInputIdxInNextLayer(logN - level, 0, jSwitched);
|
||||
// must be in upper half
|
||||
assert(jConnectedTo < (1 << (logN - 1)));
|
||||
upperPermIn[jConnectedTo] = permOut[i];
|
||||
|
||||
// Connect from j's pair to through the lower half
|
||||
int jPairConnectedTo = getInputIdxInNextLayer(logN - level, 0, jSwitched ^ 1);
|
||||
lowerPermIn[jPairConnectedTo - Nover2] = permIn[j ^ 1];
|
||||
|
||||
int iPairNext = find(permIn[j ^ 1], permOut);
|
||||
i = iPairNext ^ 1;
|
||||
} while (unmatchedIndices.contains(i));
|
||||
}
|
||||
|
||||
setInternalPermutation(upperPermIn, upperPermOut, 2*idx, level + 1);
|
||||
setInternalPermutation(lowerPermIn, lowerPermOut, 2*idx + 1, level + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermutation(int[] permutation) {
|
||||
int level = 0;
|
||||
int[] identity = new int[getNumInputs()];
|
||||
for (int i = 0; i < identity.length; ++i)
|
||||
identity[i] = i;
|
||||
|
||||
setInternalPermutation(identity, permutation, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCrossed(int layer, int switchIdx) {
|
||||
return switchValues[layer][switchIdx];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
/**
|
||||
* A generic permutation network composed of 2-input switches.
|
||||
*/
|
||||
public interface PermutationNetwork {
|
||||
/**
|
||||
* Return the number of inputs supported by the network.
|
||||
* @return
|
||||
*/
|
||||
int getNumInputs();
|
||||
|
||||
/**
|
||||
* Return the number of layers supported by the network.
|
||||
* @return
|
||||
*/
|
||||
int getNumLayers();
|
||||
|
||||
/**
|
||||
* Return the index of the switch output in the previous layer that connects to a specified input in the current layer.
|
||||
* Each consecutive pair of outputs is from the same switch, and each consecutive pair of inputs goes to the same switch.
|
||||
* (that is, switch j has inputs/outputs 2j and 2j+1)
|
||||
*
|
||||
* @param layer current layer index. Must be in the range [0, numLayers) (layer 0's previous layer consists of the inputs themselves)
|
||||
* @param inputIdx the input Idx for the current layer. Must be in the range [0, numInputs)
|
||||
*
|
||||
* @return the requested index
|
||||
*/
|
||||
int getOutputIdxInPreviousLayer(int layer, int inputIdx);
|
||||
|
||||
/**
|
||||
* The inverse of {@link }#getOutputIdxInPreviousLayer(int,int)}.
|
||||
* @param layer
|
||||
* @param inputIdx
|
||||
* @return
|
||||
*/
|
||||
int getInputIdxInNextLayer(int layer, int inputIdx);
|
||||
|
||||
/**
|
||||
* Initialize switches to generate a specific permutation.
|
||||
* @param permutation
|
||||
*/
|
||||
void setPermutation(int[] permutation);
|
||||
|
||||
|
||||
/**
|
||||
* Returns true iff the switch is crossed
|
||||
* @param layer
|
||||
* @return
|
||||
*/
|
||||
boolean isCrossed(int layer, int switchIdx);
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/17/2015.
|
||||
* container for random permutation
|
||||
* the permutation is set in the constructor and can't be changed
|
||||
*/
|
||||
public class RandomPermutation {
|
||||
public final int[] permutation;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param n permutation size
|
||||
* @param random
|
||||
*/
|
||||
public RandomPermutation(int n, Random random) {
|
||||
this.permutation = generatePermutation(n,random);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate random permutation ovver [0,n)
|
||||
* @param n permutation size
|
||||
* @param random
|
||||
* @return permutation
|
||||
*/
|
||||
public static int[] generatePermutation(int n, Random random){
|
||||
int[] result = new int[n];
|
||||
|
||||
// initialize and permute in one pass using "inside-out" Fisher-Yates
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int j = random.nextInt(i+1);
|
||||
|
||||
if (j != i) {
|
||||
result[i] = result[j];
|
||||
}
|
||||
|
||||
result[j] = i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* randomly shuffle an array of elements in-place (using Fisher-Yates)
|
||||
* @param perm array of elements to shuffle.
|
||||
* @param random
|
||||
*/
|
||||
public static <T> void permute(T[] perm, Random random){
|
||||
for (int i = perm.length - 1; i > 0; --i) {
|
||||
int j = random.nextInt(i+1);
|
||||
T tmp = perm[i];
|
||||
perm[i] = perm[j];
|
||||
perm[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
/**
|
||||
* Generic utilities
|
||||
*/
|
||||
public class Util {
|
||||
/*
|
||||
* Apply a single layer's switch permutations in place (as implied by {@link PermutationNetwork#setPermutation(int[])})
|
||||
* @param values values output by previous layxer
|
||||
* @param layer layer to apply (layer is between 1 and numLayers; layer 0 is the input layer)
|
||||
* @param <T> type of values.
|
||||
*/
|
||||
public static <T> void applyLayerSwitches(PermutationNetwork net, T[] values, int layer) {
|
||||
int numSwitches = net.getNumInputs() >>> 1;
|
||||
for (int i = 0; i < numSwitches; ++i) {
|
||||
if (net.isCrossed(layer, i)) {
|
||||
T tmp = values[i * 2];
|
||||
values[i * 2] = values[i * 2 + 1];
|
||||
values[i * 2 + 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> void convertOutputPermToInputPerm(PermutationNetwork net, T[] oldValues, T[] newValues, int layer) {
|
||||
int numInputs = net.getNumInputs();
|
||||
assert(numInputs == oldValues.length);
|
||||
assert(numInputs == newValues.length);
|
||||
|
||||
for (int i = 0; i < numInputs; ++i) {
|
||||
newValues[i] = oldValues[net.getOutputIdxInPreviousLayer(layer, i)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> void permute(PermutationNetwork net, T[] oldValues, T[] newValues) {
|
||||
for (int layer = 0; layer < net.getNumLayers(); ++layer) {
|
||||
convertOutputPermToInputPerm(net, oldValues, newValues, layer);
|
||||
applyLayerSwitches(net, newValues, layer);
|
||||
System.arraycopy(newValues, 0, oldValues, 0, oldValues.length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/01/17.
|
||||
*/
|
||||
|
||||
|
||||
public interface Concatenator {
|
||||
public interface Pair<OutType, InType1, InType2>{
|
||||
public OutType concatenate(InType1 msg1, InType2 msg2);
|
||||
public InType1 getMsg1(OutType msg);
|
||||
public InType2 getMsg2(OutType msg);
|
||||
}
|
||||
|
||||
public interface Triplet<OutType, InType1, InType2, InType3>{
|
||||
public OutType concatenate(InType1 msg1, InType2 msg2, InType3 msg3);
|
||||
public InType1 getMsg1of3(OutType msg);
|
||||
public InType2 getMsg2of3(OutType msg);
|
||||
public InType3 getMsg3of3(OutType msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Created by talm on 20/01/17.
|
||||
*/
|
||||
public interface Mix2nizk {
|
||||
/**
|
||||
* Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts.
|
||||
*/
|
||||
public interface Prover {
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the two-ciphertext mix proof
|
||||
*/
|
||||
public interface Verifier {
|
||||
/**
|
||||
* Return true iff the proof is valid.
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @return
|
||||
*/
|
||||
boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Generic Sigma Protocol.
|
||||
* The challenge is always a {@link java.math.BigInteger}.
|
||||
*/
|
||||
public interface SigmaProtocol {
|
||||
public interface Prover <FirstMsgType, FinalMessageType> {
|
||||
public FirstMsgType getFirstMessage();
|
||||
public FinalMessageType getFinalMessage(BigInteger challenge);
|
||||
}
|
||||
|
||||
public interface Simulator <FirstMsgType, FinalMessageType> {
|
||||
public FirstMsgType getFirstMessage(BigInteger challenge);
|
||||
public FinalMessageType getFinalMessage();
|
||||
}
|
||||
|
||||
public interface Verifier <FirstMsgType, FinalMessageType> {
|
||||
public boolean verify(FirstMsgType firstMessage, BigInteger challenge, FinalMessageType finalMessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.proofs.generic.SigmaProtocolAnd2;
|
||||
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, Statements.AndStatement statement,
|
||||
Statements.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<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
||||
public Simulator(ECElGamalEncryption encryptor, Random rand, Statements.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, Statements.AndStatement statement) {
|
||||
super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
||||
new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[0]), new SchnorrDlogEquivalence.Verifier(encryptor, statement.clauses[1]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.proofs.generic.SigmaProtocolOr2;
|
||||
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;
|
||||
this.rand = rand;
|
||||
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, Statements.Mix2Statement statement, Statements.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, Statements.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]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.proofs.Mix2nizk.Prover;
|
||||
import meerkat.mixer.proofs.Mix2nizk.Verifier;
|
||||
import meerkat.mixer.proofs.generic.SigmaFiatShamir;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* implements of Prover and Verifier interfaces
|
||||
* this implementation assumes that each RerandomizableEncryptedMessage is an ElGamalCiphertext
|
||||
*/
|
||||
public class Mix2nizk implements Prover, Verifier {
|
||||
//
|
||||
private final ECGroup group;
|
||||
private final Random rand;
|
||||
private final ECElGamalEncryption encryptor;
|
||||
private final Statements mixParams;
|
||||
final SigmaFiatShamir<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> mix2NIZK;
|
||||
|
||||
/**
|
||||
* @param rand
|
||||
* @param encryptor
|
||||
*/
|
||||
public Mix2nizk(Random rand, ECElGamalEncryption encryptor) {
|
||||
|
||||
this.rand = rand;
|
||||
this.encryptor = encryptor;
|
||||
this.group = this.encryptor.getGroup();
|
||||
this.mixParams = new Statements(encryptor);
|
||||
this.mix2NIZK = new SigmaFiatShamir<>(ProtobufConcatenators.concatNIZK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a
|
||||
* @param b
|
||||
* @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 layer - row of a,b in encryption table
|
||||
* @param r1
|
||||
* @param r2
|
||||
* @return - a valid ZKP that indeed c,d calculated as required
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage a,
|
||||
Crypto.RerandomizableEncryptedMessage b,
|
||||
Crypto.RerandomizableEncryptedMessage c,
|
||||
Crypto.RerandomizableEncryptedMessage d,
|
||||
boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx,
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
||||
|
||||
|
||||
Statements.Mix2Statement statement = mixParams.createStatement(a, b, c, d);
|
||||
Statements.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched);
|
||||
|
||||
Mix2.Prover prover = new Mix2.Prover(encryptor, rand, statement, witness);
|
||||
|
||||
Mixing.Mix2Proof.Location location = Mixing.Mix2Proof.Location.newBuilder()
|
||||
.setLayer(layer)
|
||||
.setSwitchIdx(switchIdx)
|
||||
.setOut0(out0Idx)
|
||||
.setOut1(out1Idx)
|
||||
.build();
|
||||
return mix2NIZK.generateNizk(prover).toBuilder().setLocation(location).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* verify zero knowledge proof
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @param proof out1 = rerandomize(in1) && out2 = rerandomize(in2)
|
||||
* ||
|
||||
* out1 = rerandomize(in2) && out2 = rerandomize(in1)
|
||||
* @return true iff all 4 or proofs are valid
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.Mix2Proof proof) throws InvalidProtocolBufferException {
|
||||
|
||||
Statements.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||
Mix2.Verifier verifier = new Mix2.Verifier(encryptor, statement);
|
||||
|
||||
return mix2NIZK.verifyNizk(proof, verifier);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.proofs.Concatenator;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/01/17.
|
||||
*/
|
||||
public class ProtobufConcatenators {
|
||||
public final static ConcatAnd1 concatAnd1 = new ConcatAnd1();
|
||||
public final static ConcatAnd2 concatAnd2 = new ConcatAnd2();
|
||||
public final static ConcatMix1 concatMix1 = new ConcatMix1();
|
||||
public final static ConcatMix2 concatMix2 = new ConcatMix2();
|
||||
public final static ConcatNIZK concatNIZK = new ConcatNIZK();
|
||||
|
||||
public static class ConcatAnd1 implements Concatenator.Pair<Mixing.Mix2Proof.AndProof.FirstMessage,Mixing.Mix2Proof.DlogProof.FirstMessage,Mixing.Mix2Proof.DlogProof.FirstMessage> {
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FirstMessage concatenate(Mixing.Mix2Proof.DlogProof.FirstMessage msg1, Mixing.Mix2Proof.DlogProof.FirstMessage msg2) {
|
||||
return Mixing.Mix2Proof.AndProof.FirstMessage.newBuilder()
|
||||
.setClause0(msg1)
|
||||
.setClause1(msg2)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.DlogProof.FirstMessage getMsg1(Mixing.Mix2Proof.AndProof.FirstMessage msg) { return msg.getClause0(); }
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.DlogProof.FirstMessage getMsg2(Mixing.Mix2Proof.AndProof.FirstMessage msg) { return msg.getClause1(); }
|
||||
}
|
||||
|
||||
public static class ConcatAnd2 implements Concatenator.Pair<Mixing.Mix2Proof.AndProof.FinalMessage,Mixing.Mix2Proof.DlogProof.FinalMessage,Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FinalMessage concatenate(Mixing.Mix2Proof.DlogProof.FinalMessage msg1, Mixing.Mix2Proof.DlogProof.FinalMessage msg2) {
|
||||
return Mixing.Mix2Proof.AndProof.FinalMessage.newBuilder()
|
||||
.setClause0(msg1)
|
||||
.setClause1(msg2)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.DlogProof.FinalMessage getMsg1(Mixing.Mix2Proof.AndProof.FinalMessage msg) { return msg.getClause0(); }
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.DlogProof.FinalMessage getMsg2(Mixing.Mix2Proof.AndProof.FinalMessage msg) { return msg.getClause1(); }
|
||||
}
|
||||
|
||||
public static class ConcatMix1 implements Concatenator.Pair<Mixing.Mix2Proof.FirstMessage,Mixing.Mix2Proof.AndProof.FirstMessage,Mixing.Mix2Proof.AndProof.FirstMessage> {
|
||||
@Override
|
||||
public Mixing.Mix2Proof.FirstMessage concatenate(Mixing.Mix2Proof.AndProof.FirstMessage msg1, Mixing.Mix2Proof.AndProof.FirstMessage msg2) {
|
||||
return Mixing.Mix2Proof.FirstMessage.newBuilder()
|
||||
.setClause0(msg1)
|
||||
.setClause1(msg2)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FirstMessage getMsg1(Mixing.Mix2Proof.FirstMessage msg) { return msg.getClause0(); }
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FirstMessage getMsg2(Mixing.Mix2Proof.FirstMessage msg) { return msg.getClause1(); }
|
||||
}
|
||||
|
||||
public static class ConcatMix2 implements Concatenator.Triplet<Mixing.Mix2Proof.FinalMessage,BigInteger,Mixing.Mix2Proof.AndProof.FinalMessage,Mixing.Mix2Proof.AndProof.FinalMessage> {
|
||||
@Override
|
||||
public Mixing.Mix2Proof.FinalMessage concatenate(BigInteger msg1, Mixing.Mix2Proof.AndProof.FinalMessage msg2, Mixing.Mix2Proof.AndProof.FinalMessage msg3) {
|
||||
return Mixing.Mix2Proof.FinalMessage.newBuilder()
|
||||
.setC0(Util.encodeBigInteger(msg1))
|
||||
.setClause0(msg2)
|
||||
.setClause1(msg3)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getMsg1of3(Mixing.Mix2Proof.FinalMessage msg) { return Util.decodeBigInteger(msg.getC0()); }
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FinalMessage getMsg2of3(Mixing.Mix2Proof.FinalMessage msg) { return msg.getClause0(); }
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.AndProof.FinalMessage getMsg3of3(Mixing.Mix2Proof.FinalMessage msg) { return msg.getClause1(); }
|
||||
}
|
||||
|
||||
|
||||
public static class ConcatNIZK implements Concatenator.Pair<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage,Mixing.Mix2Proof.FinalMessage> {
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof concatenate(Mixing.Mix2Proof.FirstMessage msg1, Mixing.Mix2Proof.FinalMessage msg2) {
|
||||
return Mixing.Mix2Proof.newBuilder()
|
||||
.setFirstMessage(msg1)
|
||||
.setFinalMessage(msg2)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.FirstMessage getMsg1(Mixing.Mix2Proof msg) {
|
||||
return msg.getFirstMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.FinalMessage getMsg2(Mixing.Mix2Proof msg) {
|
||||
return msg.getFinalMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
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 Statements.DlogStatement statement;
|
||||
|
||||
public Verifier(ECElGamalEncryption encryptor, Statements.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;
|
||||
|
||||
Statements.DlogStatement statement;
|
||||
BigInteger response = null;
|
||||
|
||||
public Simulator(ECElGamalEncryption encryptor, Random rand, Statements.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;
|
||||
Statements.DlogStatement statement;
|
||||
Statements.DlogStatementWitness witness;
|
||||
|
||||
BigInteger r = null;
|
||||
|
||||
public Prover(ECElGamalEncryption encryptor, Random rand,
|
||||
Statements.DlogStatement statement, Statements.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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Crypto.EncryptionRandomness;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* used for organizing the input for each ZKP
|
||||
*
|
||||
* both meerkat.mixProverVerifier.proofs and meerkat.mixProverVerifier.verifier implementation use it
|
||||
*/
|
||||
public class Statements {
|
||||
|
||||
final public ECElGamalEncryption encryptor;
|
||||
final public ECGroup group;
|
||||
final public ECPoint g;
|
||||
final public ECPoint h;
|
||||
|
||||
/**
|
||||
* @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 Statements(ECElGamalEncryption encryptor){
|
||||
this.encryptor = encryptor;
|
||||
this.group = encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
this.h = encryptor.getElGamalPK().getPK();
|
||||
}
|
||||
|
||||
/**
|
||||
* can be used by anyone, e.g meerkat.mixer.verifier
|
||||
*
|
||||
* call to the meerkat.mixer.main overload with trueClauseIndex = false
|
||||
*/
|
||||
public Mix2Statement createStatement(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException {
|
||||
|
||||
ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1);
|
||||
ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2);
|
||||
ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1);
|
||||
ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2);
|
||||
return new Mix2Statement(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* convert each encrypted message to ElGamalCiphertext
|
||||
*
|
||||
* @throws InvalidProtocolBufferException - in case one or more of the encrypted messages isn't
|
||||
* ElGamalCiphertext
|
||||
*/
|
||||
protected Mix2StatementWitness createMix2Witness(EncryptionRandomness r1, EncryptionRandomness r2, boolean switched) {
|
||||
// if (!switched), dlogW1 is witness for a ~ c, dlogW2 is witness for b ~ d,
|
||||
// otherwise, dlogW1 is witness for a ~ d, dlogW2 is witness for b ~ c
|
||||
DlogStatementWitness dlogW1 = new DlogStatementWitness(encryptor.extractRandomness(r1));
|
||||
DlogStatementWitness dlogW2 = new DlogStatementWitness(encryptor.extractRandomness(r2));
|
||||
|
||||
AndStatementWitness andW = new AndStatementWitness(dlogW1, dlogW2);
|
||||
|
||||
return new Mix2StatementWitness(switched ? 1 : 0, andW);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mix2Statement to be proved.
|
||||
*
|
||||
* 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 ECElGamalMixStatementGenerator (all constructors are private)
|
||||
*
|
||||
*/
|
||||
public class Mix2Statement {
|
||||
|
||||
public final AndStatement[] clauses = new AndStatement[2];
|
||||
|
||||
Mix2Statement(ElGamalCiphertext a, ElGamalCiphertext b,
|
||||
ElGamalCiphertext c, ElGamalCiphertext d){
|
||||
|
||||
ECPoint a1 = encryptor.decodeElement(a.getC1());
|
||||
ECPoint a2 = encryptor.decodeElement(a.getC2());
|
||||
ECPoint b1 = encryptor.decodeElement(b.getC1());
|
||||
ECPoint b2 = encryptor.decodeElement(b.getC2());
|
||||
ECPoint c1 = encryptor.decodeElement(c.getC1());
|
||||
ECPoint c2 = encryptor.decodeElement(c.getC2());
|
||||
ECPoint d1 = encryptor.decodeElement(d.getC1());
|
||||
ECPoint d2 = encryptor.decodeElement(d.getC2());
|
||||
|
||||
ECPoint c1_div_a1 = group.add(c1, group.negate(a1));
|
||||
ECPoint d1_div_a1 = group.add(d1, group.negate(a1));
|
||||
ECPoint c1_div_b1 = group.add(c1, group.negate(b1));
|
||||
ECPoint d1_div_b1 = group.add(d1, group.negate(b1));
|
||||
ECPoint c2_div_a2 = group.add(c2, group.negate(a2));
|
||||
ECPoint d2_div_a2 = group.add(d2, group.negate(a2));
|
||||
ECPoint c2_div_b2 = group.add(c2, group.negate(b2));
|
||||
ECPoint d2_div_b2 = group.add(d2, group.negate(b2));
|
||||
|
||||
// "Straight assignment" (a ~ c, b ~ d)
|
||||
DlogStatement s0_0 = new DlogStatement(c1_div_a1, c2_div_a2);
|
||||
DlogStatement s0_1 = new DlogStatement(d1_div_b1, d2_div_b2);
|
||||
clauses[0] = new AndStatement(s0_0, s0_1);
|
||||
|
||||
// "Switched assignment" (a ~ d, b ~ c)
|
||||
DlogStatement s1_0 = new DlogStatement(d1_div_a1, d2_div_a2);
|
||||
DlogStatement s1_1 = new DlogStatement(c1_div_b1, c2_div_b2);
|
||||
clauses[1] = new AndStatement(s1_0, s1_1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Witness information that enables us to generate a ZK proof for the 2-ciphertext mix
|
||||
*/
|
||||
public class Mix2StatementWitness {
|
||||
/**
|
||||
* Which of the two clauses is the true one
|
||||
*/
|
||||
public final int trueClauseIndex;
|
||||
|
||||
public final AndStatementWitness witness;
|
||||
|
||||
Mix2StatementWitness(int trueClauseIndex, AndStatementWitness witness) {
|
||||
|
||||
this.trueClauseIndex = trueClauseIndex;
|
||||
assert (trueClauseIndex >= 0 && trueClauseIndex < 2);
|
||||
this.witness = witness;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Statement consisting of a conjunction of two {@link DlogStatement}s
|
||||
*/
|
||||
public class AndStatement {
|
||||
public final DlogStatement[] clauses = new DlogStatement[2];
|
||||
|
||||
AndStatement(DlogStatement clause0, DlogStatement clause1) {
|
||||
this.clauses[0] = clause0;
|
||||
this.clauses[1] = clause1;
|
||||
}
|
||||
}
|
||||
|
||||
public class AndStatementWitness {
|
||||
public final DlogStatementWitness[] witnesses = new DlogStatementWitness[2];
|
||||
|
||||
AndStatementWitness(DlogStatementWitness witness0, DlogStatementWitness witness1) {
|
||||
this.witnesses[0] = witness0;
|
||||
this.witnesses[1] = witness1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters for a statement of discrete-log equality
|
||||
*
|
||||
* log_{g}(a)==log_{h}(b)
|
||||
*/
|
||||
public class DlogStatement {
|
||||
public final ECPoint g;
|
||||
public final ECPoint a;
|
||||
public final ECPoint h;
|
||||
public final ECPoint b;
|
||||
|
||||
|
||||
DlogStatement(ECPoint a, ECPoint b) {
|
||||
this.g = Statements.this.g;
|
||||
this.a = a;
|
||||
this.h = Statements.this.h;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Witness for correctness of a {@link DlogStatement}
|
||||
*/
|
||||
public class DlogStatementWitness {
|
||||
/**
|
||||
* The actual discrete logarithm (i.e., a=g^x, b=h^x)
|
||||
*/
|
||||
BigInteger x;
|
||||
|
||||
public DlogStatementWitness(BigInteger x) {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package meerkat.mixer.proofs.generic;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.mixer.proofs.Concatenator;
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Transform a Sigma protocol into a NIZK using Fiat-Shamir
|
||||
* We use SHA-256 explicitly to make it easier to verify in other codebases
|
||||
*/
|
||||
public class SigmaFiatShamir<NIZKMsgType, FirstMsgType extends Message, FinalMessageType> {
|
||||
final static String DIGEST_ALG = "SHA-256";
|
||||
final MessageDigest md;
|
||||
final Concatenator.Pair<NIZKMsgType, FirstMsgType, FinalMessageType> concat;
|
||||
|
||||
public SigmaFiatShamir(Concatenator.Pair<NIZKMsgType, FirstMsgType, FinalMessageType> concat) {
|
||||
this.concat = concat;
|
||||
try {
|
||||
md = MessageDigest.getInstance(DIGEST_ALG);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Should never happen
|
||||
throw new RuntimeException("Error in instantiating " + DIGEST_ALG + " digest", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fiat–Shamir heuristic
|
||||
* @param input - protobuf contains all parameters from the first step of the current proof
|
||||
* @return randomOracle.hash(input)
|
||||
*/
|
||||
public BigInteger hash(Message input) {
|
||||
md.reset();
|
||||
|
||||
byte[] arr = input.toByteArray();
|
||||
byte[] digest = md.digest(arr);
|
||||
return new BigInteger(1,digest);
|
||||
}
|
||||
|
||||
public NIZKMsgType generateNizk(SigmaProtocol.Prover<FirstMsgType, FinalMessageType> prover) {
|
||||
FirstMsgType firstMessage = prover.getFirstMessage();
|
||||
BigInteger challenge = hash(firstMessage);
|
||||
FinalMessageType finalMessage = prover.getFinalMessage(challenge);
|
||||
return concat.concatenate(firstMessage, finalMessage);
|
||||
}
|
||||
|
||||
public boolean verifyNizk(NIZKMsgType NIZK, SigmaProtocol.Verifier<FirstMsgType, FinalMessageType> verifier) {
|
||||
FirstMsgType firstMessage = concat.getMsg1(NIZK);
|
||||
BigInteger challenge = hash(firstMessage);
|
||||
return verifier.verify(firstMessage, challenge, concat.getMsg2(NIZK));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package meerkat.mixer.proofs.generic;
|
||||
|
||||
import meerkat.mixer.proofs.Concatenator;
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Generic conjuction of sigma protocols
|
||||
*/
|
||||
public class SigmaProtocolAnd2 {
|
||||
static public class Prover <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Prover<FirstMessageOut, FinalMessageOut> {
|
||||
final SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn>[] provers;
|
||||
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
|
||||
@SafeVarargs
|
||||
public Prover(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn>... provers) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.provers = provers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FirstMessageOut getFirstMessage() {
|
||||
return firstMessageConcatenator.concatenate(provers[0].getFirstMessage(), provers[1].getFirstMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinalMessageOut getFinalMessage(BigInteger challenge) {
|
||||
return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(challenge));
|
||||
}
|
||||
}
|
||||
|
||||
static public class Verifier<FirstMessageOut, FirstMessageIn,
|
||||
FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Verifier<FirstMessageOut, FinalMessageOut> {
|
||||
final SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>[] verifiers;
|
||||
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
|
||||
@SafeVarargs
|
||||
public Verifier(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>... verifiers) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.verifiers = verifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(FirstMessageOut firstMessage, BigInteger challenge, FinalMessageOut finalMessage) {
|
||||
return verifiers[0].verify(firstMessageConcatenator.getMsg1(firstMessage), challenge, finalMessageConcatenator.getMsg1(finalMessage)) &&
|
||||
verifiers[1].verify(firstMessageConcatenator.getMsg2(firstMessage), challenge, finalMessageConcatenator.getMsg2(finalMessage));
|
||||
}
|
||||
}
|
||||
|
||||
static public class Simulator <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Simulator<FirstMessageOut, FinalMessageOut> {
|
||||
final SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn>[] simulators;
|
||||
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
|
||||
@SafeVarargs
|
||||
public Simulator(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn>... simulators) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.simulators = simulators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FirstMessageOut getFirstMessage(BigInteger challenge) {
|
||||
return firstMessageConcatenator.concatenate(simulators[0].getFirstMessage(challenge), simulators[1].getFirstMessage(challenge));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinalMessageOut getFinalMessage() {
|
||||
return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package meerkat.mixer.proofs.generic;
|
||||
|
||||
import meerkat.mixer.proofs.Concatenator;
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Disjunction of 2 Sigma protocol statements
|
||||
*/
|
||||
public class SigmaProtocolOr2 {
|
||||
public interface ChallengeGenerator {
|
||||
|
||||
/**
|
||||
* Generate a random challenge in an appropriate way (e.g., mod group order)
|
||||
* @return
|
||||
*/
|
||||
public BigInteger generateChallenge();
|
||||
|
||||
/**
|
||||
* Subtract two challenges in an appropriate way (e.g., mod group order)
|
||||
* @param c1
|
||||
* @param c2
|
||||
* @return
|
||||
*/
|
||||
public BigInteger subtractChallenge(BigInteger c1, BigInteger c2);
|
||||
}
|
||||
|
||||
static public class Prover <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Prover<FirstMessageOut, FinalMessageOut> {
|
||||
final SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn> prover;
|
||||
final SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn> simulator;
|
||||
final int proverIdx;
|
||||
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
final ChallengeGenerator challengeGenerator;
|
||||
|
||||
BigInteger simChallenge;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param prover
|
||||
* @param simulator
|
||||
* @param proverIdx Which index should the prover be inserted at (0 means first, 1 means second)
|
||||
*/
|
||||
public Prover(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
ChallengeGenerator challengeGenerator,
|
||||
SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn> prover,
|
||||
SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn> simulator, int proverIdx) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.challengeGenerator = challengeGenerator;
|
||||
this.prover = prover;
|
||||
this.simulator = simulator;
|
||||
this.proverIdx = proverIdx;
|
||||
assert (proverIdx >= 0 && proverIdx < 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FirstMessageOut getFirstMessage() {
|
||||
simChallenge = challengeGenerator.generateChallenge();
|
||||
if (proverIdx == 0) {
|
||||
return firstMessageConcatenator.concatenate(prover.getFirstMessage(), simulator.getFirstMessage(simChallenge));
|
||||
} else {
|
||||
return firstMessageConcatenator.concatenate(simulator.getFirstMessage(simChallenge), prover.getFirstMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FinalMessageOut getFinalMessage(BigInteger challenge) {
|
||||
BigInteger realchallenge = challengeGenerator.subtractChallenge(challenge, simChallenge);
|
||||
if (proverIdx == 0) {
|
||||
return finalMessageConcatenator.concatenate(realchallenge, prover.getFinalMessage(realchallenge), simulator.getFinalMessage());
|
||||
} else {
|
||||
return finalMessageConcatenator.concatenate(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class Verifier <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Verifier<FirstMessageOut, FinalMessageOut> {
|
||||
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
|
||||
final ChallengeGenerator challengeGenerator;
|
||||
|
||||
final SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>[] verifiers;
|
||||
|
||||
@SafeVarargs
|
||||
public Verifier(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
ChallengeGenerator challengeGenerator,
|
||||
SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>... verifiers) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.challengeGenerator = challengeGenerator;
|
||||
|
||||
this.verifiers = verifiers;
|
||||
}
|
||||
|
||||
public boolean verify(FirstMessageOut firstMessage, BigInteger challenge, FinalMessageOut finalMessage) {
|
||||
BigInteger firstChallenge = finalMessageConcatenator.getMsg1of3(finalMessage);
|
||||
BigInteger secondChallenge = challengeGenerator.subtractChallenge(challenge, firstChallenge);
|
||||
return verifiers[0].verify(firstMessageConcatenator.getMsg1(firstMessage), firstChallenge, finalMessageConcatenator.getMsg2of3(finalMessage)) &
|
||||
verifiers[1].verify(firstMessageConcatenator.getMsg2(firstMessage), secondChallenge, finalMessageConcatenator.getMsg3of3(finalMessage));
|
||||
}
|
||||
}
|
||||
|
||||
static public class Simulator<FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
|
||||
implements SigmaProtocol.Simulator<FirstMessageOut, FinalMessageOut> {
|
||||
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
|
||||
final Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
|
||||
|
||||
final ChallengeGenerator challengeGenerator;
|
||||
|
||||
final SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn>[] simulators;
|
||||
|
||||
|
||||
BigInteger simChallenge0;
|
||||
|
||||
|
||||
@SafeVarargs
|
||||
public Simulator(Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator,
|
||||
Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator,
|
||||
ChallengeGenerator challengeGenerator, SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn>... simulators) {
|
||||
this.firstMessageConcatenator = firstMessageConcatenator;
|
||||
this.finalMessageConcatenator = finalMessageConcatenator;
|
||||
this.challengeGenerator = challengeGenerator;
|
||||
this.simulators = simulators;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FirstMessageOut getFirstMessage(BigInteger challenge) {
|
||||
|
||||
simChallenge0 = challengeGenerator.generateChallenge();
|
||||
BigInteger simChallenge1 = challengeGenerator.subtractChallenge(challenge, simChallenge0);
|
||||
|
||||
return firstMessageConcatenator.concatenate(simulators[0].getFirstMessage(simChallenge0), simulators[1].getFirstMessage(simChallenge1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinalMessageOut getFinalMessage() {
|
||||
return finalMessageConcatenator.concatenate(simChallenge0, simulators[0].getFinalMessage(), simulators[1].getFinalMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,303 +0,0 @@
|
|||
package meerkat.mixer.prover;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
/**
|
||||
* use for organize the input for each ZKP
|
||||
*
|
||||
* both meerkat.mixer.prover and meerkat.mixer.verifier implantation are using it
|
||||
*/
|
||||
public class ElGamalProofOrganizer {
|
||||
|
||||
private final ECGroup group;
|
||||
private final ECPoint g;
|
||||
private final ECPoint h;
|
||||
private final byte[] gEncoded;
|
||||
private final byte[] hEncoded;
|
||||
|
||||
/**
|
||||
* @param group
|
||||
* @param g - generator of group
|
||||
* @param h - h = g ^ SecretKey
|
||||
*/
|
||||
public ElGamalProofOrganizer(ECGroup group, ECPoint g, ECPoint h){
|
||||
this.group = group;
|
||||
this.g = g;
|
||||
this.h = h;
|
||||
this.gEncoded = group.encode(g);
|
||||
this.hEncoded = group.encode(h);
|
||||
}
|
||||
|
||||
public enum OrProofOrder {
|
||||
first, second, third, fourth
|
||||
}
|
||||
|
||||
public enum TrueCouple {
|
||||
left, right, unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* can be used by meerkat.mixer.prover only
|
||||
*
|
||||
* call to the meerkat.mixer.main overload with flag = true
|
||||
*/
|
||||
protected ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2
|
||||
, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2
|
||||
, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) throws InvalidProtocolBufferException {
|
||||
|
||||
//boolean flag = true;
|
||||
return createProofInput(in1,in2,out1,out2,r1,r2,switched,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* can be used by anyone, e.g meerkat.mixer.verifier
|
||||
*
|
||||
* call to the meerkat.mixer.main overload with flag = false
|
||||
*/
|
||||
public ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2
|
||||
, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException {
|
||||
|
||||
// flag = false;
|
||||
return createProofInput(in1,in2,out1,out2,null,null,false,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* inner method
|
||||
* convert each encrypted message to ElGamalCiphertext
|
||||
*
|
||||
* @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known)
|
||||
* @return ElGamalProofInput
|
||||
* @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't
|
||||
* ElGamalCiphertext
|
||||
*/
|
||||
private ElGamalProofInput createProofInput(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2
|
||||
, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2
|
||||
, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag)
|
||||
throws InvalidProtocolBufferException {
|
||||
|
||||
//convert RerandomizableEncryptedMessage to ElGamalCiphertext
|
||||
ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1);
|
||||
ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2);
|
||||
ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1);
|
||||
ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2);
|
||||
|
||||
if(flag) {
|
||||
return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched);
|
||||
}else {
|
||||
return new ElGamalProofInput(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* can be construct by instance of organizer only by calling createProofInput method (all constructors are private)
|
||||
*
|
||||
* in construction it use for preparing the input for prove, while avoiding double converting or calculations
|
||||
*
|
||||
* use as a container for 4 OrProofInput.
|
||||
*/
|
||||
public class ElGamalProofInput {
|
||||
|
||||
private final OrProofInput first;
|
||||
private final OrProofInput second;
|
||||
private final OrProofInput third;
|
||||
private final OrProofInput fourth;
|
||||
|
||||
private ECPoint convert2ECPoint(ByteString bs){
|
||||
return group.decode(bs.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param flag - true if called by meerkat.mixer.prover ( r1,r2,switched are known)
|
||||
*/
|
||||
private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2
|
||||
, ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New
|
||||
, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched,boolean flag){
|
||||
|
||||
ECPoint e1c1 = convert2ECPoint(e1.getC1());
|
||||
ECPoint e1c2 = convert2ECPoint(e1.getC2());
|
||||
ECPoint e2c1 = convert2ECPoint(e2.getC1());
|
||||
ECPoint e2c2 = convert2ECPoint(e2.getC2());
|
||||
ECPoint e1Nc1 = convert2ECPoint(e1New.getC1());
|
||||
ECPoint e1Nc2 = convert2ECPoint(e1New.getC2());
|
||||
ECPoint e2Nc1 = convert2ECPoint(e2New.getC1());
|
||||
ECPoint e2Nc2 = convert2ECPoint(e2New.getC2());
|
||||
|
||||
ECPoint c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1));
|
||||
ECPoint c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1));
|
||||
ECPoint c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1));
|
||||
ECPoint c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1));
|
||||
|
||||
ECPoint c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2));
|
||||
ECPoint c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2));
|
||||
ECPoint c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2));
|
||||
ECPoint c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2));
|
||||
|
||||
|
||||
if(!flag){
|
||||
|
||||
this.first = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2);
|
||||
this.second = new OrProofInput(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1);
|
||||
this.third = new OrProofInput(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2);
|
||||
this.fourth = new OrProofInput(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2);
|
||||
|
||||
}else {
|
||||
|
||||
byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1);
|
||||
byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1);
|
||||
byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2);
|
||||
byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2);
|
||||
byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1);
|
||||
byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1);
|
||||
byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2);
|
||||
byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2);
|
||||
|
||||
|
||||
if (!switched) {
|
||||
this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded
|
||||
, r1, TrueCouple.left);
|
||||
this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded
|
||||
, r1, TrueCouple.left);
|
||||
this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.right);
|
||||
this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.right);
|
||||
} else {
|
||||
this.first = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded
|
||||
, r2, TrueCouple.right);
|
||||
this.second = new OrProofInput(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded
|
||||
, r1, TrueCouple.right);
|
||||
this.third = new OrProofInput(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.left);
|
||||
this.fourth = new OrProofInput(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r1, TrueCouple.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* used by the meerkat.mixer.prover
|
||||
* call to the meerkat.mixer.main constructor with flag = true
|
||||
*/
|
||||
private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2
|
||||
, ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New
|
||||
, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched){
|
||||
//flag = true;
|
||||
this(e1,e2,e1New,e2New,r1,r2,switched,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* used by meerkat.mixer.prover
|
||||
* call to the meerkat.mixer.main constructor with flag = true
|
||||
*/
|
||||
private ElGamalProofInput(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2
|
||||
, ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){
|
||||
//flag = false;
|
||||
this(e1,e2,e1New,e2New,null,null,false,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for all 4 OrProofInputs
|
||||
*
|
||||
* @param orProofOrder
|
||||
* @return the required OrProof
|
||||
*/
|
||||
public OrProofInput getOrProofInput(OrProofOrder orProofOrder) {
|
||||
switch (orProofOrder) {
|
||||
|
||||
case first:
|
||||
return this.first;
|
||||
case second:
|
||||
return this.second;
|
||||
case third:
|
||||
return this.third;
|
||||
case fourth:
|
||||
return this.fourth;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* can't be constructed (all constructors are private)
|
||||
*
|
||||
* 4 instances will be constructed for each new ElGamalProofInput
|
||||
*
|
||||
* container for all meerkat.mixer.necessary inputs for single OrProof
|
||||
*/
|
||||
public class OrProofInput{
|
||||
public final ECPoint g1;
|
||||
public final ECPoint h1;
|
||||
public final ECPoint g2;
|
||||
public final ECPoint h2;
|
||||
public final ECPoint g1Tag;
|
||||
public final ECPoint h1Tag;
|
||||
public final ECPoint g2Tag;
|
||||
public final ECPoint h2Tag;
|
||||
|
||||
// can be access by meerkat.mixer.prover only
|
||||
protected final byte[] g1Encoded;
|
||||
protected final byte[] h1Encoded;
|
||||
protected final byte[] g2Encoded;
|
||||
protected final byte[] h2Encoded;
|
||||
protected final byte[] g1TagEncoded;
|
||||
protected final byte[] h1TagEncoded;
|
||||
protected final byte[] g2TagEncoded;
|
||||
protected final byte[] h2TagEncoded;
|
||||
protected final Crypto.EncryptionRandomness x;
|
||||
protected final TrueCouple flag;
|
||||
|
||||
/**
|
||||
* used by meerkat.mixer.prover only
|
||||
*/
|
||||
private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag
|
||||
,byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded
|
||||
, Crypto.EncryptionRandomness x, TrueCouple flag) {
|
||||
this.g1 = g;
|
||||
this.h1 = h1;
|
||||
this.g2 = h;
|
||||
this.h2 = h2;
|
||||
this.g1Tag = g;
|
||||
this.h1Tag = h1Tag;
|
||||
this.g2Tag = h;
|
||||
this.h2Tag = h2Tag;
|
||||
|
||||
this.g1Encoded = gEncoded;
|
||||
this.h1Encoded = h1Encoded;
|
||||
this.g2Encoded = hEncoded;
|
||||
this.h2Encoded = h2Encoded;
|
||||
this.g1TagEncoded = gEncoded;
|
||||
this.h1TagEncoded = h1TagEncoded;
|
||||
this.g2TagEncoded = hEncoded;
|
||||
this.h2TagEncoded = h2TagEncoded;
|
||||
|
||||
this.x = x;
|
||||
this.flag = flag;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* used by meerkat.mixer.verifier
|
||||
*/
|
||||
private OrProofInput(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) {
|
||||
this(h1,h2,h1Tag,h2Tag,null,null,null,null,null,TrueCouple.unknown);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
package meerkat.mixer.prover;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.RandomOracle;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* implements of Mix2ZeroKnowledgeProver interface
|
||||
* this implementation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext
|
||||
*/
|
||||
public class Prover implements Mix2ZeroKnowledgeProver {
|
||||
|
||||
private final ECGroup group;
|
||||
private final RandomOracle randomOracle;
|
||||
private final Random rand;
|
||||
private final ECElGamalEncryption encryptor;
|
||||
private final ECPoint g,h;
|
||||
private final BigInteger groupOrderUpperBound;
|
||||
private final ElGamalProofOrganizer organizer;
|
||||
|
||||
/**
|
||||
* @param rand
|
||||
* @param encryptor
|
||||
* @param randomOracle - use for Fiat–Shamir heuristic
|
||||
*/
|
||||
public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) {
|
||||
|
||||
this.rand = rand;
|
||||
this.encryptor = encryptor;
|
||||
this.randomOracle = randomOracle;
|
||||
this.group = this.encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
this.h = this.encryptor.getElGamalPK().getPK();
|
||||
this.organizer = new ElGamalProofOrganizer(group,g,h);
|
||||
this.groupOrderUpperBound = group.orderUpperBound();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1)
|
||||
* @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2)
|
||||
* @param sw - flag
|
||||
* @param i - column of in1 and out1 in encryption table
|
||||
* @param j - column of in2 and out2 in encryption table
|
||||
* @param layer - row of in1,in2 in encryption table
|
||||
* @param r1
|
||||
* @param r2
|
||||
* @return - a valid ZKP that indeed out1,out2 calculated as required
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
boolean sw,int i,int j, int layer,
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
||||
Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth;
|
||||
|
||||
ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw);
|
||||
|
||||
first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first));
|
||||
second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second));
|
||||
third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third));
|
||||
fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth));
|
||||
|
||||
Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
|
||||
.setI(i)
|
||||
.setJ(j)
|
||||
.setLayer(layer)
|
||||
.build();
|
||||
|
||||
Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder()
|
||||
.setFirst(first)
|
||||
.setSecond(second)
|
||||
.setThird(third)
|
||||
.setFourth(fourth)
|
||||
.setLocation(location)
|
||||
.build();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fiat–Shamir heuristic
|
||||
* @param input - protobuf contains all parameters from the first step of the current prove
|
||||
* @param randomOracle
|
||||
* @return randomOracle.hash(input)
|
||||
*/
|
||||
public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input, RandomOracle randomOracle) {
|
||||
byte[] arr = input.toByteArray();
|
||||
return new BigInteger(1,randomOracle.hash(arr,arr.length));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param orProofInput
|
||||
* @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2)
|
||||
* assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.prover
|
||||
*/
|
||||
private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) {
|
||||
|
||||
ECPoint g1 = orProofInput.g1;
|
||||
ECPoint h1 = orProofInput.h1;
|
||||
ECPoint g2 = orProofInput.g2;
|
||||
ECPoint h2 = orProofInput.h2;
|
||||
|
||||
ECPoint g1Tag = orProofInput.g1Tag;
|
||||
ECPoint h1Tag = orProofInput.h1Tag;
|
||||
ECPoint g2Tag = orProofInput.g2Tag;
|
||||
ECPoint h2Tag = orProofInput.h2Tag;
|
||||
|
||||
BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
|
||||
BigInteger c1,c2,z,zTag;
|
||||
ECPoint u,v,uTag,vTag;
|
||||
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle;
|
||||
|
||||
|
||||
switch (orProofInput.flag) {
|
||||
case left:
|
||||
c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
|
||||
zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
|
||||
//step 1
|
||||
u = group.multiply(g1, r);
|
||||
v = group.multiply(g2, r);
|
||||
uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2)));
|
||||
vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2)));
|
||||
//step 2
|
||||
// c1 = (hash(input + step1) + group size - c2)% group size
|
||||
forRandomOracle =
|
||||
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
|
||||
.setG1(ByteString.copyFrom(orProofInput.g1Encoded))
|
||||
.setH1(ByteString.copyFrom(orProofInput.h1Encoded))
|
||||
.setG2(ByteString.copyFrom(orProofInput.g2Encoded))
|
||||
.setH2(ByteString.copyFrom(orProofInput.h2Encoded))
|
||||
.setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded))
|
||||
.setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded))
|
||||
.setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded))
|
||||
.setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded))
|
||||
.setU(ByteString.copyFrom(group.encode(u)))
|
||||
.setV(ByteString.copyFrom(group.encode(v)))
|
||||
.setUTag(ByteString.copyFrom(group.encode(uTag)))
|
||||
.setVTag(ByteString.copyFrom(group.encode(vTag)))
|
||||
.build();
|
||||
c1 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
|
||||
//step 3
|
||||
//z = (r + c1 * x) % group size;
|
||||
z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound);
|
||||
break;
|
||||
case right:
|
||||
c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
|
||||
z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
|
||||
//step 1
|
||||
uTag = group.multiply(g1Tag, r);
|
||||
vTag = group.multiply(g2Tag, r);
|
||||
u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1)));
|
||||
v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1)));
|
||||
//step 2
|
||||
// c1 = (hash(input + step1) + group size - c1)% group size
|
||||
forRandomOracle =
|
||||
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
|
||||
.setG1(ByteString.copyFrom(orProofInput.g1Encoded))
|
||||
.setH1(ByteString.copyFrom(orProofInput.h1Encoded))
|
||||
.setG2(ByteString.copyFrom(orProofInput.g2Encoded))
|
||||
.setH2(ByteString.copyFrom(orProofInput.h2Encoded))
|
||||
.setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded))
|
||||
.setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded))
|
||||
.setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded))
|
||||
.setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded))
|
||||
.setU(ByteString.copyFrom(group.encode(u)))
|
||||
.setV(ByteString.copyFrom(group.encode(v)))
|
||||
.setUTag(ByteString.copyFrom(group.encode(uTag)))
|
||||
.setVTag(ByteString.copyFrom(group.encode(vTag)))
|
||||
.build();
|
||||
c2 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
|
||||
//step 3
|
||||
//zTag = (r + c2 * x) % group size;
|
||||
zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
|
||||
.setG1(forRandomOracle.getG1())
|
||||
.setH1(forRandomOracle.getH1())
|
||||
.setG2(forRandomOracle.getG2())
|
||||
.setH2(forRandomOracle.getH2())
|
||||
.setG1Tag(forRandomOracle.getG1())
|
||||
.setH1Tag(forRandomOracle.getH1Tag())
|
||||
.setG2Tag(forRandomOracle.getG2Tag())
|
||||
.setH2Tag(forRandomOracle.getH2Tag())
|
||||
.setU(forRandomOracle.getU())
|
||||
.setV(forRandomOracle.getV())
|
||||
.setUTag(forRandomOracle.getUTag())
|
||||
.setVTag(forRandomOracle.getVTag())
|
||||
.setC1(ByteString.copyFrom(c1.toByteArray()))
|
||||
.setC2(ByteString.copyFrom(c2.toByteArray()))
|
||||
.setZ(ByteString.copyFrom(z.toByteArray()))
|
||||
.setZTag(ByteString.copyFrom(zTag.toByteArray()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
package meerkat.mixer.verifier;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import meerkat.mixer.prover.ElGamalProofOrganizer;
|
||||
import meerkat.mixer.prover.Prover;
|
||||
import org.factcenter.qilin.primitives.RandomOracle;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
/**
|
||||
* implements Mix2ZeroKnowledgeVerifier
|
||||
*/
|
||||
public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
||||
|
||||
|
||||
private final ECGroup group;
|
||||
private final RandomOracle randomOracle;
|
||||
private final ECPoint g,h;
|
||||
private final ElGamalProofOrganizer organizer;
|
||||
private final ZeroKnowledgeOrProofParser parser;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param encryptor should be as the encryptor used by meerkat.mixer.prover
|
||||
* @param randomOracle should be as the random oracle used by meerkat.mixer.prover
|
||||
*/
|
||||
public Verifier(ECElGamalEncryption encryptor, RandomOracle randomOracle) {
|
||||
this.group = encryptor.getGroup();
|
||||
this.g = group.getGenerator();
|
||||
this.h = encryptor.getElGamalPK().getPK();
|
||||
this.randomOracle = randomOracle;
|
||||
this.organizer = new ElGamalProofOrganizer(group,g,h);
|
||||
this.parser = new ZeroKnowledgeOrProofParser(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* verify zero knowledge proof
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @param proof out1 = rerandomize(in1) && out2 = rerandomize(in2)
|
||||
* ||
|
||||
* out1 = rerandomize(in2) && out2 = rerandomize(in1)
|
||||
* @return true iff all 4 or proofs are valid
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException {
|
||||
ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2);
|
||||
return verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first), proof.getFirst())&&
|
||||
verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second), proof.getSecond())&&
|
||||
verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third), proof.getThird())&&
|
||||
verifyElGamaOrProof(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth), proof.getFourth());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orProofInput
|
||||
* @param orProof
|
||||
* @return verify single or proof
|
||||
*/
|
||||
private boolean verifyElGamaOrProof(ElGamalProofOrganizer.OrProofInput orProofInput,
|
||||
Mixing.ZeroKnowledgeProof.OrProof orProof) {
|
||||
ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof);
|
||||
return container.g1.equals(orProofInput.g1) &&
|
||||
container.h1.equals(orProofInput.h1) &&
|
||||
container.g2.equals(orProofInput.g2) &&
|
||||
container.h2.equals(orProofInput.h2) &&
|
||||
container.g1Tag.equals(orProofInput.g1Tag) &&
|
||||
container.h1Tag.equals(orProofInput.h1Tag) &&
|
||||
container.g2Tag.equals(orProofInput.g2Tag) &&
|
||||
container.h2Tag.equals(orProofInput.h2Tag) &&
|
||||
container.c1.add(container.c2).mod(group.orderUpperBound())
|
||||
.equals(Prover.hash(container.forRandomOracle,randomOracle).mod(group.orderUpperBound())) &&
|
||||
group.multiply(container.g1, container.z)
|
||||
.equals(group.add(container.u, group.multiply(container.h1,container.c1))) &&
|
||||
group.multiply(container.g2, container.z)
|
||||
.equals(group.add(container.v, group.multiply(container.h2,container.c1))) &&
|
||||
group.multiply(container.g1Tag, container.zTag)
|
||||
.equals(group.add(container.uTag, group.multiply(container.h1Tag,container.c2))) &&
|
||||
group.multiply(container.g2Tag, container.zTag)
|
||||
.equals(group.add(container.vTag, group.multiply(container.h2Tag,container.c2)));
|
||||
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package meerkat.mixer.verifier;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.crypto.mixnet.MixerOutput;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/30/2015.
|
||||
* provide one operation - verify meerkat.mixer.mixing output
|
||||
*/
|
||||
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)
|
||||
throws InvalidProtocolBufferException {
|
||||
int index1,index2,layer;
|
||||
|
||||
//assert n = 2^k
|
||||
if ( (n &(n-1)) != 0)
|
||||
throw new IllegalArgumentException("n");
|
||||
|
||||
int layers = 2*(int)(Math.log(n) / Math.log(2)) - 1;
|
||||
//initialize locationChecksum table
|
||||
// use for check BeneshNet validity
|
||||
boolean[][] locationChecksum = new boolean[layers][n];
|
||||
for (boolean[] locationChecksumLayer: locationChecksum) {
|
||||
Arrays.fill(locationChecksumLayer,false);
|
||||
}
|
||||
|
||||
Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs();
|
||||
Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages();
|
||||
|
||||
for (int i = 0; i < zeroKnowledgeProofs.length ; i++){
|
||||
for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){
|
||||
Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j];
|
||||
Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation();
|
||||
index1 = location.getI();
|
||||
index2 = location.getJ();
|
||||
layer = location.getLayer();
|
||||
|
||||
// check location validity
|
||||
if (layer > layers >> 1) {
|
||||
if (index2 - index1 != n >> (layers - layer))
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
if (index2 - index1 != n >> (layer + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
// mark location in table
|
||||
locationChecksum[layer][index1] = true;
|
||||
locationChecksum[layer][index2] = true;
|
||||
|
||||
// verify proof
|
||||
if(!verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
||||
rerandomizableEncryptedMessages[layer][index2],
|
||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
||||
zkp)) {
|
||||
|
||||
verifier.verify(rerandomizableEncryptedMessages[layer][index1],
|
||||
rerandomizableEncryptedMessages[layer][index2],
|
||||
rerandomizableEncryptedMessages[layer + 1][index1],
|
||||
rerandomizableEncryptedMessages[layer + 1][index2],
|
||||
zkp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify all meerkat.mixer.necessary locations for BeneshNet were proved
|
||||
for (boolean[] checksumLayer: locationChecksum) {
|
||||
for (boolean locationBoolean: checksumLayer) {
|
||||
if (!locationBoolean)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package meerkat.mixer.verifier;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/25/2016.
|
||||
* zero knowledge proof parser
|
||||
*/
|
||||
public class ZeroKnowledgeOrProofParser {
|
||||
|
||||
private final ECGroup group;
|
||||
|
||||
/**
|
||||
* parse or proof message and return the result in zero knowledge or proof container
|
||||
* @param orProof
|
||||
* @return zero knowledge or proof container
|
||||
*/
|
||||
public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){
|
||||
return new ZeroKnowledgeOrProofContainer(orProof);
|
||||
}
|
||||
|
||||
/**
|
||||
* getter
|
||||
* @param group
|
||||
*/
|
||||
public ZeroKnowledgeOrProofParser(ECGroup group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert ByteString to ECPoint
|
||||
* @param bs
|
||||
* @return
|
||||
*/
|
||||
public ECPoint convert2ECPoint(ByteString bs){
|
||||
return group.decode(bs.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* inner class
|
||||
* container for parsed zero knowledge or proof
|
||||
* constructor is private, can be construct using ZeroKnowledgeOrProofParser.parseOrProof
|
||||
*/
|
||||
public class ZeroKnowledgeOrProofContainer{
|
||||
public final ECPoint g1,g2,h1,h2;
|
||||
public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag;
|
||||
public final ECPoint u,v,uTag,vTag;
|
||||
public final BigInteger c1,c2,z,zTag;
|
||||
public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param orProof
|
||||
*/
|
||||
private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){
|
||||
this.forRandomOracle =
|
||||
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
|
||||
.setG1(orProof.getG1())
|
||||
.setH1(orProof.getH1())
|
||||
.setG2(orProof.getG2())
|
||||
.setH2(orProof.getH2())
|
||||
.setG1Tag(orProof.getG1Tag())
|
||||
.setH1Tag(orProof.getH1Tag())
|
||||
.setG2Tag(orProof.getG2Tag())
|
||||
.setH2Tag(orProof.getH2Tag())
|
||||
.setU(orProof.getU())
|
||||
.setV(orProof.getV())
|
||||
.setUTag(orProof.getUTag())
|
||||
.setVTag(orProof.getVTag())
|
||||
.build();
|
||||
this.g1 = convert2ECPoint(orProof.getG1());
|
||||
this.g2 = convert2ECPoint(orProof.getG2());
|
||||
this.h1 = convert2ECPoint(orProof.getH1());
|
||||
this.h2 = convert2ECPoint(orProof.getH2());
|
||||
this.g1Tag = convert2ECPoint(orProof.getG1Tag());
|
||||
this.g2Tag = convert2ECPoint(orProof.getG2Tag());
|
||||
this.h1Tag = convert2ECPoint(orProof.getH1Tag());
|
||||
this.h2Tag = convert2ECPoint(orProof.getH2Tag());
|
||||
this.u = convert2ECPoint(orProof.getU());
|
||||
this.v = convert2ECPoint(orProof.getV());
|
||||
this.uTag = convert2ECPoint(orProof.getUTag());
|
||||
this.vTag = convert2ECPoint(orProof.getVTag());
|
||||
this.c1 = new BigInteger(orProof.getC1().toByteArray());
|
||||
this.c2 = new BigInteger(orProof.getC2().toByteArray());
|
||||
this.z = new BigInteger(orProof.getZ().toByteArray());
|
||||
this.zTag = new BigInteger(orProof.getZTag().toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package meerkat;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
message Mix2Proof {
|
||||
// Proof that log_g(a) = log_h(b) = x
|
||||
message DlogProof {
|
||||
message FirstMessage {
|
||||
GroupElement gr = 1; // g^r
|
||||
GroupElement hr = 2; // h^r
|
||||
}
|
||||
message FinalMessage {
|
||||
BigInteger xcr = 1; // xc+r, where c is the challenge
|
||||
}
|
||||
}
|
||||
|
||||
message AndProof {
|
||||
message FirstMessage {
|
||||
DlogProof.FirstMessage clause0 = 1;
|
||||
DlogProof.FirstMessage clause1 = 2;
|
||||
}
|
||||
message FinalMessage {
|
||||
DlogProof.FinalMessage clause0 = 1;
|
||||
DlogProof.FinalMessage clause1 = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message FirstMessage {
|
||||
AndProof.FirstMessage clause0 = 1;
|
||||
AndProof.FirstMessage clause1 = 2;
|
||||
}
|
||||
message FinalMessage {
|
||||
AndProof.FinalMessage clause0 = 1;
|
||||
AndProof.FinalMessage clause1 = 2;
|
||||
BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0
|
||||
}
|
||||
|
||||
|
||||
// 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.prover.Prover;
|
||||
import meerkat.mixer.verifier.Verifier;
|
||||
import meerkat.mixer.verifier.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(encryptor,randomOracle,true);
|
||||
//Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,encryptor,randomOracle,true);
|
||||
//mixer = new Mixer(randomMixer,corruptedProver,encryptor,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.mixProverVerifier.proofs.Mix2nizk.Prover;
|
||||
//import meerkat.mixProverVerifier.proofs.Mix2nizk.Verifier;
|
||||
//import meerkat.mixProverVerifier.Mixer;
|
||||
//import meerkat.mixProverVerifier.MixerOutput;
|
||||
//import meerkat.mixProverVerifier.proofs.Prover;
|
||||
//import meerkat.mixProverVerifier.proofs.Verifier;
|
||||
//import meerkat.mixProverVerifier.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;
|
||||
// Verifier verifier;
|
||||
// Prover prover;
|
||||
// meerkat.crypto.mixnet.Mixer mixProverVerifier;
|
||||
// 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.encodePK(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);
|
||||
// mixProverVerifier = 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 network");
|
||||
// MixerOutput mixerOutput = (MixerOutput)mixProverVerifier.mix(mixerInput,randomMixer);
|
||||
// System.out.println("network 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 {
|
||||
//
|
||||
// //Verifier corruptedVerifier = new Verifier(enc,randomOracle,true);
|
||||
// //Prover corruptedProver = new Prover(randomProver,enc,randomOracle,true);
|
||||
// //mixProverVerifier = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
|
||||
//
|
||||
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
// System.out.println("start network");
|
||||
// MixerOutput mixerOutput = (MixerOutput)mixProverVerifier.mix(mixerInput,random);
|
||||
// System.out.println("network 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");
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package meerkat.mixer;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
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 java.math.BigInteger;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Base class with common parameters.
|
||||
*/
|
||||
public class ECParamTestBase {
|
||||
|
||||
public Random rand;
|
||||
public ECElGamal.SK key;
|
||||
public ECGroup group;
|
||||
public ECElGamalEncryption enc;
|
||||
public ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
|
||||
public ECParamTestBase() {
|
||||
rand = new Random(1);
|
||||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
try {
|
||||
enc.init(serializedPk);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
e.printStackTrace();
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -5,18 +5,9 @@ package meerkat.mixer;
|
|||
*/
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.mixer.mixing.Mixer;
|
||||
import meerkat.mixer.prover.Prover;
|
||||
import meerkat.mixer.verifier.Verifier;
|
||||
import meerkat.mixer.verifier.VerifyTable;
|
||||
import meerkat.mixer.proofs.concrete.Mix2nizk;
|
||||
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 org.junit.Test;
|
||||
|
||||
|
@ -25,45 +16,33 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class MixingTest {
|
||||
|
||||
ECElGamalEncryption encryptor;
|
||||
ECGroup group;
|
||||
public class MixingTest extends ECParamTestBase {
|
||||
Random random,randomMixer,randomProver;
|
||||
RandomOracle randomOracle;
|
||||
Mix2ZeroKnowledgeVerifier verifier;
|
||||
Prover prover;
|
||||
meerkat.crypto.mixnet.Mixer mixer;
|
||||
private int layers;
|
||||
Mix2nizk mix2nizk;
|
||||
MixGenerator mixer;
|
||||
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);
|
||||
random = new Random(1);
|
||||
randomMixer = new Random(2);
|
||||
randomProver = new Random(3);
|
||||
mix2nizk = new Mix2nizk(randomProver, enc);
|
||||
mixer = new MixGenerator(mix2nizk, enc);
|
||||
|
||||
// generate n
|
||||
int logN = 8; // + random.nextInt(8)
|
||||
layers = 2*logN - 1;
|
||||
int logN = 5; // + random.nextInt(8)
|
||||
n = 1 << logN;
|
||||
}
|
||||
|
||||
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){
|
||||
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(int n){
|
||||
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)));
|
||||
result.add(enc.encrypt(msg, enc.generateRandomness(random)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -72,11 +51,11 @@ public class MixingTest {
|
|||
public void mixingTest() throws InvalidProtocolBufferException {
|
||||
System.out.println("n is : " + n);
|
||||
System.out.println(" generating input");
|
||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
|
||||
System.out.println(" start mixing");
|
||||
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput(n);
|
||||
System.out.println(" start network");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
meerkat.crypto.mixnet.MixerOutput mixerOutput = mixer.mix(mixerInput,randomMixer);
|
||||
MixerOutput mixerOutput = mixer.mix(mixerInput,randomMixer);
|
||||
|
||||
long finishTime = System.currentTimeMillis();
|
||||
System.out.println(" that took: "+(finishTime-startTime)+ " ms");
|
||||
|
@ -84,7 +63,7 @@ public class MixingTest {
|
|||
System.out.println("start verification");
|
||||
startTime = System.currentTimeMillis();
|
||||
|
||||
assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
|
||||
assert (MixVerifier.verifyTable(mix2nizk, mixerOutput, true));
|
||||
|
||||
finishTime = System.currentTimeMillis();
|
||||
System.out.println(" that took: "+(finishTime-startTime)+ " ms");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package meerkat.mixer;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
|
@ -35,7 +35,7 @@ public class RerandomizeTest {
|
|||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
RandomOracle randomOracle = new DigestOracle();
|
||||
|
@ -43,8 +43,8 @@ public class RerandomizeTest {
|
|||
h = enc.getElGamalPK().getPK();
|
||||
}
|
||||
|
||||
private ECPoint convert2ECPoint(ByteString bs){
|
||||
return group.decode(bs.toByteArray());
|
||||
private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
|
||||
return enc.decodeElement(bs);
|
||||
}
|
||||
|
||||
public void oneRerandomizeTest() throws InvalidProtocolBufferException {
|
||||
|
@ -56,8 +56,8 @@ public class RerandomizeTest {
|
|||
Crypto.RerandomizableEncryptedMessage e = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
Crypto.RerandomizableEncryptedMessage eNew = enc.rerandomize(e, r);
|
||||
|
||||
assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg));
|
||||
assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg));
|
||||
assert (Util.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg));
|
||||
assert (Util.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg));
|
||||
|
||||
ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e);
|
||||
ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew);
|
||||
|
|
|
@ -27,67 +27,7 @@ import java.util.Random;
|
|||
* Created by Tzlil on 1/1/2016.
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
|
||||
public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH";
|
||||
/**
|
||||
* Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption}
|
||||
* @param pk
|
||||
* @return
|
||||
*/
|
||||
public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK<ECPoint> pk) {
|
||||
ECPoint pkPoint = pk.getPK();
|
||||
ECParameterSpec params = group.getCurveParams();
|
||||
|
||||
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
|
||||
|
||||
try {
|
||||
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
|
||||
GlobalCryptoSetup.getInstance().getBouncyCastleProvider());
|
||||
PublicKey javaPk = fact.generatePublic(pubKeySpec);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder()
|
||||
.setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build();
|
||||
|
||||
return serializedPk;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error converting public key!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard (non-threshold) decryption for testing purposes.
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ByteString c1encoded = cipherText.getC1();
|
||||
ByteString c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = group.decode(c1encoded.toByteArray());
|
||||
ECPoint c2 = group.decode(c2encoded.toByteArray());
|
||||
|
||||
assert (group.contains(c1));
|
||||
assert (group.contains(c2));
|
||||
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
|
||||
|
||||
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
|
||||
|
||||
try {
|
||||
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
|
||||
Message.Builder builder = (Message.Builder) newBuilder.invoke(plaintextMessageType);
|
||||
builder.mergeDelimitedFrom(in);
|
||||
return plaintextMessageType.cast(builder.build());
|
||||
} catch (Exception e) {
|
||||
throw new InvalidProtocolBufferException("Plaintext protobuf error");
|
||||
}
|
||||
}
|
||||
|
||||
static Random random = new Random();
|
||||
static Random random = new Random(0);
|
||||
|
||||
public static Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) {
|
||||
Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder();
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package meerkat.mixer.main;
|
||||
|
||||
import com.google.protobuf.StringValue;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 21/01/17.
|
||||
*/
|
||||
public class MixTest {
|
||||
public Mix mix;
|
||||
Random rand = new Random(1);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mix = new Mix();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeygen() throws Exception {
|
||||
File tmpKeys = File.createTempFile("elgamal", "key");
|
||||
mix.createKeypair(tmpKeys);
|
||||
|
||||
ECElGamal.SK secretKey = mix.secretKey;
|
||||
assertNotNull(secretKey);
|
||||
assertNotNull(mix.serializedPk);
|
||||
|
||||
Mix newMix = new Mix();
|
||||
|
||||
newMix.loadKeypair(tmpKeys);
|
||||
assertEquals(mix.serializedPk, newMix.serializedPk);
|
||||
|
||||
StringValue tst = StringValue.newBuilder().setValue("test").build();
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage cipher = mix.enc.encrypt(tst, mix.enc.generateRandomness(rand));
|
||||
StringValue newTst = Util.decrypt(StringValue.class, newMix.secretKey, newMix.enc.getGroup(), cipher);
|
||||
|
||||
assertEquals(tst, newTst);
|
||||
|
||||
}
|
||||
|
||||
File createPlaintexts(int n) throws Exception {
|
||||
File tmpData = File.createTempFile("plaintext", "txt");
|
||||
PrintStream out = new PrintStream(tmpData);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
out.println("Line " + i);
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
return tmpData;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncryptDecrypt() throws Exception {
|
||||
File tmpKeys = File.createTempFile("elgamal", "key");
|
||||
mix.createKeypair(tmpKeys);
|
||||
|
||||
int n = 35;
|
||||
File plaintexts = createPlaintexts(n);
|
||||
File ciphertexts = File.createTempFile("ciphertexts", "bin");
|
||||
mix.encrypt(plaintexts, ciphertexts);
|
||||
|
||||
Mix newMix = new Mix();
|
||||
newMix.loadKeypair(tmpKeys);
|
||||
newMix.loadMix(ciphertexts);
|
||||
File newPlaintexts = File.createTempFile("plaintexts2", "txt");
|
||||
newMix.decrypt(newPlaintexts);
|
||||
|
||||
BufferedReader in1 = new BufferedReader(new FileReader(plaintexts));
|
||||
BufferedReader in2 = new BufferedReader(new FileReader(newPlaintexts));
|
||||
|
||||
int n2 = 1 << newMix.inMix.getLogN();
|
||||
assert(n2 >= n);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
String line1 = in1.readLine();
|
||||
String line2 = in2.readLine();
|
||||
assertEquals(line1, line2);
|
||||
}
|
||||
|
||||
for (int i = n; i < n2; ++i) {
|
||||
String line2 = in2.readLine();
|
||||
assertEquals("", line2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMixVerify() throws Exception {
|
||||
File tmpKeys = File.createTempFile("elgamal", "key");
|
||||
mix.createKeypair(tmpKeys);
|
||||
|
||||
int n = 35;
|
||||
File plaintexts = createPlaintexts(n);
|
||||
File ciphertexts = File.createTempFile("ciphertexts", "enc");
|
||||
mix.encrypt(plaintexts, ciphertexts);
|
||||
|
||||
File mixedFile = File.createTempFile("mixed", "enc");
|
||||
Mix newMix1 = new Mix();
|
||||
newMix1.loadKeypair(tmpKeys);
|
||||
newMix1.loadMix(ciphertexts);
|
||||
newMix1.mix(mixedFile);
|
||||
|
||||
Mix newMix2 = new Mix();
|
||||
newMix2.loadKeypair(tmpKeys);
|
||||
newMix2.loadMix(mixedFile);
|
||||
boolean ok = newMix2.verify(true);
|
||||
assertTrue(ok);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
/**
|
||||
* Tests for Benes Network topology
|
||||
*/
|
||||
public class BenesNetworkTest extends PermutationNetworkTest {
|
||||
final static int logN = 8;
|
||||
|
||||
@Override
|
||||
protected PermutationNetwork getNewNetwork() {
|
||||
return new BenesNetwork(logN);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package meerkat.mixer.network;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Generically Test a permutation network
|
||||
*/
|
||||
abstract public class PermutationNetworkTest {
|
||||
|
||||
public static final int NUM_REPS = 10;
|
||||
Random rand;
|
||||
|
||||
abstract protected PermutationNetwork getNewNetwork();
|
||||
|
||||
PermutationNetwork network;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
network = getNewNetwork();
|
||||
rand = new Random(1);
|
||||
}
|
||||
|
||||
public static Set<Integer> getSequenceSet(int N) {
|
||||
Set<Integer> set = new TreeSet<>();
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
set.add(i);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
public static Integer[] getSequenceArray(int N) {
|
||||
Integer[] arr = new Integer[N];
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
arr[i] = i;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a given network is actually a permutation network (i.e., always
|
||||
* implies a permutation regardless of 2x2 switch settings).
|
||||
*/
|
||||
@Test
|
||||
public void isAlwaysAPermutation() {
|
||||
int numLayers = network.getNumLayers();
|
||||
int N = network.getNumInputs();
|
||||
|
||||
for (int layer = 1; layer < numLayers; ++layer) {
|
||||
Set<Integer> unusedInputs = getSequenceSet(N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
unusedInputs.remove(network.getOutputIdxInPreviousLayer(layer, i));
|
||||
}
|
||||
assertTrue("Not a permutation! Didn't use: " + unusedInputs, unusedInputs.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardEqualsBackwards() {
|
||||
int numLayers = network.getNumLayers();
|
||||
int N = network.getNumInputs();
|
||||
|
||||
for (int layer = 1; layer < numLayers; ++layer) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
int j = network.getOutputIdxInPreviousLayer(layer, i);
|
||||
assertEquals(String.format("Input %d in layer %d has problems", i, layer), i,
|
||||
network.getInputIdxInNextLayer(layer - 1, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] convert(Integer[] in) {
|
||||
int[] out = new int[in.length];
|
||||
for (int i = 0; i < in.length; ++i)
|
||||
out[i] = in[i];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomPermutations() throws Exception {
|
||||
for (int rep = 0; rep < NUM_REPS; ++rep) {
|
||||
Integer[] target = getSequenceArray(network.getNumInputs());
|
||||
RandomPermutation.permute(target, rand);
|
||||
|
||||
network.setPermutation(convert(target));
|
||||
|
||||
Integer[] id = getSequenceArray(network.getNumInputs());
|
||||
|
||||
Integer[] out = new Integer[target.length];
|
||||
|
||||
Util.permute(network, id, out);
|
||||
|
||||
assertArrayEquals("Permutation mismatch: " + target + " != " + out, target, out);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.Crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* A dummy proof that can be used for testing
|
||||
*/
|
||||
public class DummySigmaProof {
|
||||
public static class Prover implements SigmaProtocol.Prover<Crypto.BigInteger,BigInteger> {
|
||||
|
||||
/**
|
||||
* The "statement" to be proved: x + y = z
|
||||
*/
|
||||
|
||||
final BigInteger x,y,z;
|
||||
final BigInteger r;
|
||||
|
||||
public Prover(BigInteger x, BigInteger y, BigInteger z, BigInteger r) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.BigInteger getFirstMessage() {
|
||||
return Util.encodeBigInteger(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getFinalMessage(BigInteger challenge) {
|
||||
return challenge.add(r.multiply(x.add(y)));
|
||||
}
|
||||
}
|
||||
public static class Verifier implements SigmaProtocol.Verifier<Crypto.BigInteger,BigInteger> {
|
||||
|
||||
final BigInteger x,y,z;
|
||||
|
||||
public Verifier(BigInteger x, BigInteger y, BigInteger z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(Crypto.BigInteger firstMessage, BigInteger challenge, BigInteger finalMessage) {
|
||||
BigInteger r = Util.decodeBigInteger(firstMessage);
|
||||
return finalMessage.equals(challenge.add(r.multiply(z)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Simulator implements SigmaProtocol.Simulator<Crypto.BigInteger,BigInteger> {
|
||||
|
||||
final BigInteger x,y,z;
|
||||
|
||||
BigInteger resp;
|
||||
|
||||
public Simulator(BigInteger x, BigInteger y, BigInteger z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Crypto.BigInteger getFirstMessage(BigInteger challenge) {
|
||||
BigInteger r = BigInteger.ONE;
|
||||
resp = challenge.add(z);
|
||||
return Util.encodeBigInteger(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getFinalMessage() {
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by talm on 14/01/17.
|
||||
*/
|
||||
public class DummySigmaTest extends SigmaProtocolTest<Crypto.BigInteger, BigInteger> {
|
||||
BigInteger seed;
|
||||
BigInteger x,y,z;
|
||||
|
||||
@Override
|
||||
protected void generateRandomTrueStatement() {
|
||||
x = new BigInteger(100, rand); y = new BigInteger(100, rand); z = x.add(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomFalseStatement() {
|
||||
x = new BigInteger(100, rand);
|
||||
y = new BigInteger(100, rand);
|
||||
z = new BigInteger(100, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Prover<Crypto.BigInteger, BigInteger> getNewProver() {
|
||||
return new DummySigmaProof.Prover(x, y, z, new BigInteger(100, rand));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Verifier<Crypto.BigInteger, BigInteger> getNewVerifier() {
|
||||
return new DummySigmaProof.Verifier(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Simulator<Crypto.BigInteger, BigInteger> getNewSimulator() {
|
||||
return new DummySigmaProof.Simulator(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger getChallengeModulus() {
|
||||
return new BigInteger(100, rand);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.mixer.proofs.generic.SigmaFiatShamir;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Generic test for Sigma Protocol
|
||||
*/
|
||||
abstract public class SigmaProtocolTest<M1 extends Message, M2> {
|
||||
public final int NUM_REPEAT = 10;
|
||||
|
||||
abstract protected void generateRandomTrueStatement();
|
||||
|
||||
abstract protected void generateRandomFalseStatement();
|
||||
|
||||
abstract protected SigmaProtocol.Prover<M1, M2> getNewProver();
|
||||
abstract protected SigmaProtocol.Verifier<M1, M2> getNewVerifier();
|
||||
abstract protected SigmaProtocol.Simulator<M1, M2> getNewSimulator();
|
||||
|
||||
public class NIZKConcat implements Concatenator.Pair<Pair<M1,M2>, M1, M2> {
|
||||
@Override
|
||||
public Pair<M1, M2> concatenate(M1 msg1, M2 msg2) { return new Pair<M1, M2>(msg1, msg2); }
|
||||
|
||||
@Override
|
||||
public M1 getMsg1(Pair<M1,M2> msg) { return msg.a; }
|
||||
|
||||
@Override
|
||||
public M2 getMsg2(Pair<M1,M2> msg) { return msg.b; }
|
||||
}
|
||||
|
||||
final protected NIZKConcat nizkConcat = new NIZKConcat();
|
||||
|
||||
abstract protected BigInteger getChallengeModulus();
|
||||
|
||||
SigmaProtocol.Prover<M1, M2> prover;
|
||||
SigmaProtocol.Verifier<M1, M2> verifier;
|
||||
SigmaProtocol.Simulator<M1, M2> simulator;
|
||||
BigInteger challengeModulus;
|
||||
int challengeBits;
|
||||
|
||||
protected Random rand = new Random(1);;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
challengeModulus = getChallengeModulus();
|
||||
challengeBits = challengeModulus.bitLength() + 1;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProverCompleteness() {
|
||||
for (int i = 0; i < NUM_REPEAT; ++i) {
|
||||
generateRandomTrueStatement();
|
||||
|
||||
prover = getNewProver();
|
||||
verifier = getNewVerifier();
|
||||
|
||||
M1 msg1 = prover.getFirstMessage();
|
||||
BigInteger c = new BigInteger(challengeBits, rand).mod(challengeModulus);
|
||||
M2 msg2 = prover.getFinalMessage(c);
|
||||
|
||||
assertTrue(String.format("Verification error in iteration %d", i), verifier.verify(msg1, c, msg2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSimulatorCompleteness() {
|
||||
for (int i = 0; i < NUM_REPEAT; ++i) {
|
||||
generateRandomFalseStatement();
|
||||
|
||||
simulator = getNewSimulator();
|
||||
verifier = getNewVerifier();
|
||||
|
||||
BigInteger c = new BigInteger(challengeBits, rand).mod(challengeModulus);
|
||||
|
||||
M1 msg1 = simulator.getFirstMessage(c);
|
||||
M2 msg2 = simulator.getFinalMessage();
|
||||
|
||||
assertTrue(String.format("Simulator Verification error in iteration %d", i), verifier.verify(msg1, c, msg2));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNIZKCompleteness() {
|
||||
for (int i = 0; i < NUM_REPEAT; ++i) {
|
||||
generateRandomTrueStatement();
|
||||
|
||||
SigmaFiatShamir<Pair<M1,M2>, M1, M2> fiatShamir = new SigmaFiatShamir<Pair<M1,M2>, M1, M2>(nizkConcat);
|
||||
|
||||
prover = getNewProver();
|
||||
Pair<M1,M2> nizk = fiatShamir.generateNizk(prover);
|
||||
|
||||
verifier = getNewVerifier();
|
||||
boolean nizkOk = fiatShamir.verifyNizk(nizk, verifier);
|
||||
|
||||
assertTrue(String.format("NIZK Verification error in iteration %d", i), nizkOk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
import meerkat.mixer.proofs.SigmaProtocolTest;
|
||||
import meerkat.mixer.proofs.generic.SigmaProtocolAnd2;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/01/17.
|
||||
*/
|
||||
public class DlogAndStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
|
||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||
|
||||
Statements.DlogStatement s1, s2;
|
||||
Statements.DlogStatementWitness w1, w2;
|
||||
|
||||
public DlogAndStatementSigmaTest() {
|
||||
this.dlogtest = new DlogStatementSchnorrSigmaTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomTrueStatement() {
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
s1 = s1w1.a; w1 = s1w1.b;
|
||||
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
s2 = s2w2.a; w2 = s2w2.b;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomFalseStatement() {
|
||||
s1 = dlogtest.returnRandomFalseStatement();
|
||||
s2 = dlogtest.returnRandomFalseStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
|
||||
return new SigmaProtocolAnd2.Prover<>(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2,
|
||||
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,
|
||||
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,
|
||||
new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s1), new SchnorrDlogEquivalence.Simulator(dlogtest.encryptor, rand, s2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger getChallengeModulus() {
|
||||
return dlogtest.getChallengeModulus();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
import meerkat.mixer.proofs.SigmaProtocolTest;
|
||||
import meerkat.mixer.proofs.generic.SigmaProtocolOr2;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by talm on 14/01/17.
|
||||
*/
|
||||
public class DlogOrStatementSigmaTest extends SigmaProtocolTest<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> {
|
||||
final DlogStatementSchnorrSigmaTest dlogtest;
|
||||
|
||||
final Statements.AndStatement[] statements = new Statements.AndStatement[2];
|
||||
Statements.AndStatementWitness w;
|
||||
int trueStatementIndex;
|
||||
|
||||
|
||||
public DlogOrStatementSigmaTest() {
|
||||
this.dlogtest = new DlogStatementSchnorrSigmaTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomTrueStatement() {
|
||||
trueStatementIndex = rand.nextInt(2);
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> s1w1 = dlogtest.returnRandomTrueStatement();
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> s2w2 = dlogtest.returnRandomTrueStatement();
|
||||
Statements.AndStatement trueStatement = dlogtest.statementGenerator.new AndStatement(s1w1.a, s2w2.a);
|
||||
w = dlogtest.statementGenerator.new AndStatementWitness(s1w1.b, s2w2.b);
|
||||
statements[trueStatementIndex] = trueStatement;
|
||||
|
||||
Statements.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
Statements.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
|
||||
Statements.AndStatement falseStatement = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||
|
||||
statements[1 - trueStatementIndex] = falseStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomFalseStatement() {
|
||||
Statements.DlogStatement f1 = dlogtest.returnRandomFalseStatement();
|
||||
Statements.DlogStatement f2 = dlogtest.returnRandomFalseStatement();
|
||||
|
||||
statements[0] = dlogtest.statementGenerator.new AndStatement(f1, f2);
|
||||
|
||||
f1 = dlogtest.returnRandomFalseStatement();
|
||||
f2 = dlogtest.returnRandomFalseStatement();
|
||||
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 = 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,
|
||||
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,
|
||||
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<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage,
|
||||
Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage>(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2,
|
||||
gen, new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[0]),
|
||||
new DlogConjunction.Simulator(dlogtest.encryptor, rand, statements[1]));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger getChallengeModulus() {
|
||||
return dlogtest.getChallengeModulus();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.ECParamTestBase;
|
||||
import meerkat.mixer.proofs.SigmaProtocol;
|
||||
import meerkat.mixer.proofs.SigmaProtocolTest;
|
||||
import meerkat.mixer.proofs.concrete.SchnorrDlogEquivalence;
|
||||
import meerkat.mixer.proofs.concrete.Statements;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/01/17.
|
||||
*/
|
||||
public class DlogStatementSchnorrSigmaTest extends
|
||||
SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
|
||||
|
||||
ECParamTestBase ecParams;
|
||||
Statements statementGenerator;
|
||||
ECElGamalEncryption encryptor;
|
||||
ECGroup group;
|
||||
|
||||
Statements.DlogStatement statement;
|
||||
Statements.DlogStatementWitness witness;
|
||||
SchnorrDlogEquivalence.Prover prover;
|
||||
SchnorrDlogEquivalence.Verifier verifier;
|
||||
SchnorrDlogEquivalence.Simulator simulator;
|
||||
|
||||
public DlogStatementSchnorrSigmaTest() {
|
||||
ecParams = new ECParamTestBase();
|
||||
encryptor = ecParams.enc;
|
||||
group = encryptor.getGroup();
|
||||
this.statementGenerator = new Statements(ecParams.enc);
|
||||
}
|
||||
|
||||
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> returnRandomTrueStatement() {
|
||||
BigInteger x = encryptor.generateRandomExponent(rand);
|
||||
ECPoint a = group.multiply(statementGenerator.g, x);
|
||||
ECPoint b = group.multiply(statementGenerator.h, x);
|
||||
Statements.DlogStatement statement = statementGenerator.new DlogStatement(a, b);
|
||||
Statements.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x);
|
||||
|
||||
return new Pair<>(statement, witness);
|
||||
}
|
||||
|
||||
Statements.DlogStatement returnRandomFalseStatement() {
|
||||
ECPoint a = group.sample(rand);
|
||||
ECPoint b = group.sample(rand);
|
||||
|
||||
return statementGenerator.new DlogStatement(a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomTrueStatement() {
|
||||
Pair<Statements.DlogStatement, Statements.DlogStatementWitness> sw = returnRandomTrueStatement();
|
||||
this.statement = sw.a;
|
||||
this.witness = sw.b;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateRandomFalseStatement() {
|
||||
witness = null;
|
||||
statement = returnRandomFalseStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
|
||||
prover = new SchnorrDlogEquivalence.Prover(encryptor, rand, statement, witness);
|
||||
return prover;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
|
||||
verifier = new SchnorrDlogEquivalence.Verifier(encryptor, statement);
|
||||
return verifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewSimulator() {
|
||||
simulator = new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement);
|
||||
return simulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger getChallengeModulus() {
|
||||
return group.orderUpperBound();
|
||||
}
|
||||
}
|
|
@ -1,58 +1,38 @@
|
|||
package meerkat.mixer;
|
||||
package meerkat.mixer.proofs.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier;
|
||||
import meerkat.mixer.prover.Prover;
|
||||
import meerkat.mixer.verifier.Verifier;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.ECParamTestBase;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import meerkat.protobuf.Voting;
|
||||
//import meerkat.protobuf.Voting.PlaintextBallot;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
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 org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 12/31/2015.
|
||||
*/
|
||||
public class ZeroKnowledgeProofTest {
|
||||
|
||||
Random rand;
|
||||
ECElGamal.SK key;
|
||||
ECGroup group;
|
||||
ECElGamalEncryption enc;
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
Mix2ZeroKnowledgeVerifier verifier ;
|
||||
Mix2ZeroKnowledgeProver prover ;
|
||||
public class Mix2ProofTest extends ECParamTestBase {
|
||||
Mix2nizk nizk;
|
||||
meerkat.mixer.proofs.Mix2nizk.Verifier verifier ;
|
||||
meerkat.mixer.proofs.Mix2nizk.Prover prover ;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
rand = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
RandomOracle randomOracle = new DigestOracle();
|
||||
verifier = new Verifier(enc,randomOracle);
|
||||
prover = new Prover(new Random(),enc,randomOracle);
|
||||
nizk = new Mix2nizk(rand, enc);
|
||||
verifier = nizk;
|
||||
prover = nizk;
|
||||
}
|
||||
|
||||
private ECPoint convert2ECPoint(ByteString bs){
|
||||
return group.decode(bs.toByteArray());
|
||||
private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
|
||||
return enc.decodeElement(bs);
|
||||
}
|
||||
|
||||
public void oneZKPTest() throws InvalidProtocolBufferException {
|
||||
|
@ -66,10 +46,10 @@ public class ZeroKnowledgeProofTest {
|
|||
Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1);
|
||||
Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2);
|
||||
|
||||
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1), msg1);
|
||||
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1New), msg1);
|
||||
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2), msg2);
|
||||
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2New), msg2);
|
||||
assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1), msg1);
|
||||
assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1New), msg1);
|
||||
assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2), msg2);
|
||||
assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2New), msg2);
|
||||
|
||||
ECPoint g = group.getGenerator();
|
||||
ECPoint h = enc.getElGamalPK().getPK();
|
||||
|
@ -89,11 +69,14 @@ public class ZeroKnowledgeProofTest {
|
|||
assertEquals (h.multiply(enc.extractRandomness(r2)),
|
||||
group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));
|
||||
|
||||
assertTrue (verifier.verify(e1,e2,e1New,e2New,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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException {
|
||||
public void Mix2ProofTest() throws InvalidProtocolBufferException {
|
||||
|
||||
int tests = 1000;
|
||||
|
|
@ -2,6 +2,7 @@ package profiling.BigInteger;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
|
@ -28,7 +29,7 @@ public class AddSub {
|
|||
ECGroup group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
ECElGamal.SK key = new ECElGamal.SK(group, sk);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
|
||||
ECElGamalEncryption enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package profiling.BigInteger;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
|
@ -25,7 +26,7 @@ public class GenerateRandomness {
|
|||
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
ECElGamal.SK key = new ECElGamal.SK(group, sk);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package profiling.BigInteger;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
|
@ -27,7 +27,7 @@ public class Modulo {
|
|||
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
ECElGamal.SK key = new ECElGamal.SK(group, sk);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
|
||||
ECElGamalEncryption enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
for (int i =0 ; i < tests ; i++){
|
||||
|
|
|
@ -2,6 +2,7 @@ package profiling.BigInteger;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
|
@ -28,7 +29,7 @@ public class Mul {
|
|||
ECGroup group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
ECElGamal.SK key = new ECElGamal.SK(group, sk);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
|
||||
ECElGamalEncryption enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package profiling.Convert;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
@ -30,7 +30,7 @@ public class ByteString2ECPoint {
|
|||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
tests = 1024 * 19;
|
||||
|
@ -45,8 +45,8 @@ public class ByteString2ECPoint {
|
|||
(enc.encrypt(msg, enc.generateRandomness(rand)));
|
||||
}
|
||||
}
|
||||
private ECPoint convert2ECPoint(ByteString bs){
|
||||
return group.decode(bs.toByteArray());
|
||||
private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
|
||||
return enc.decodeElement(bs);
|
||||
}
|
||||
|
||||
public void ByteString2ECPointProfiling() throws InvalidProtocolBufferException {
|
||||
|
|
|
@ -2,6 +2,7 @@ package profiling.Convert;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
|
@ -29,7 +30,7 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext {
|
|||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
tests = 1024 * 18;
|
||||
|
|
|
@ -2,7 +2,7 @@ package profiling.ECGroup;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
@ -29,7 +29,7 @@ public class Add {
|
|||
random = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
encryptor = new ECElGamalEncryption();
|
||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
// generate n;
|
||||
int sqrtn = 128;
|
||||
n = sqrtn*sqrtn;
|
||||
|
|
|
@ -2,6 +2,7 @@ package profiling.ECGroup;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
|
@ -29,7 +30,7 @@ public class Encode {
|
|||
random = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
encryptor = new ECElGamalEncryption();
|
||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
// generate n;
|
||||
int sqrtn = 128;
|
||||
n = sqrtn*sqrtn;
|
||||
|
|
|
@ -2,7 +2,7 @@ package profiling.ECGroup;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
@ -30,7 +30,7 @@ public class Mul {
|
|||
random = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
encryptor = new ECElGamalEncryption();
|
||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
// generate n
|
||||
int sqrtn = 128;
|
||||
n = sqrtn*sqrtn;
|
||||
|
|
|
@ -2,7 +2,7 @@ package profiling.ECGroup;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
@ -28,7 +28,7 @@ public class Negate {
|
|||
random = new Random();
|
||||
group = new ECGroup("secp256k1");
|
||||
encryptor = new ECElGamalEncryption();
|
||||
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
|
||||
// generate n;
|
||||
int sqrtn = 128;
|
||||
n = sqrtn*sqrtn;
|
||||
|
|
|
@ -2,10 +2,11 @@ package profiling;
|
|||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.Utils;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.mixer.Utils;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
|
@ -31,7 +32,7 @@ public class Rerandomize {
|
|||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
int LogVotes = 10;
|
||||
|
|
|
@ -3,8 +3,8 @@ package profiling;
|
|||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
|
||||
import meerkat.mixer.prover.Prover;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.mixer.proofs.concrete.Mix2nizk;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
|
@ -28,22 +28,21 @@ public class ZeroKnowledgeProof {
|
|||
ECGroup group;
|
||||
ECElGamalEncryption enc;
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
Mix2ZeroKnowledgeProver prover ;
|
||||
meerkat.mixer.proofs.Mix2nizk.Prover prover ;
|
||||
int n;
|
||||
Crypto.EncryptionRandomness[] randomnesses;
|
||||
Crypto.RerandomizableEncryptedMessage[] encryptedMessage;
|
||||
Crypto.RerandomizableEncryptedMessage[] reencryptedMessage;
|
||||
|
||||
public void setup() throws Exception {
|
||||
rand = new Random();
|
||||
rand = new Random(1);
|
||||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = Utils.serializePk(group, key);
|
||||
serializedPk = Util.encodePK(group, key);
|
||||
enc = new ECElGamalEncryption();
|
||||
enc.init(serializedPk);
|
||||
RandomOracle randomOracle = new DigestOracle();
|
||||
prover = new Prover(new Random(),enc,randomOracle);
|
||||
prover = new Mix2nizk(rand,enc);
|
||||
int LogVotes = 12;
|
||||
int layers = 2*LogVotes - 1;
|
||||
n = layers * (1<<LogVotes) / 2;
|
||||
|
@ -75,7 +74,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();
|
||||
|
|
|
@ -21,13 +21,12 @@ apply plugin: 'maven-publish'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat polling-station application"
|
||||
|
@ -43,21 +42,10 @@ dependencies {
|
|||
compile project(':meerkat-common')
|
||||
compile project(':restful-api-common')
|
||||
|
||||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.5.+'
|
||||
|
||||
// Servlets
|
||||
compile 'org.eclipse.jetty:jetty-server:9.3.+'
|
||||
compile 'org.eclipse.jetty:jetty-servlet:9.3.+'
|
||||
|
||||
// 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.+'
|
||||
|
@ -137,21 +125,6 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
|
@ -159,13 +132,15 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -187,12 +162,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,16 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
|||
* This method is called by the Jetty engine when instantiating the servlet
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() throws Exception{
|
||||
callbacks = (Iterable<FutureCallback<PollingStation.ScannedData>>) servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME);
|
||||
@SuppressWarnings("unchecked")
|
||||
public void init() throws Exception {
|
||||
Object context = servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME);
|
||||
|
||||
try {
|
||||
callbacks = (Iterable<FutureCallback<PollingStation.ScannedData>>) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@POST
|
||||
|
|
|
@ -18,13 +18,12 @@ apply plugin: 'maven-publish'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Common classes for implementing Meerkat's RESTful API"
|
||||
|
@ -42,14 +41,6 @@ dependencies {
|
|||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
||||
|
||||
// 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.+'
|
||||
|
@ -95,21 +86,6 @@ idea {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
|
@ -117,13 +93,15 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -145,12 +123,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,12 @@ apply plugin: 'maven-publish'
|
|||
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') : ""
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
|
||||
// Credentials for publishing repositories
|
||||
publishRepository = "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
publishUser = project.hasProperty('publishUser') ? project.property('publishUser') : ""
|
||||
publishPassword = project.hasProperty('publishPassword') ? project.property('publishPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat voting booth application"
|
||||
|
@ -41,22 +40,11 @@ dependencies {
|
|||
compile project(':meerkat-common')
|
||||
compile project(':restful-api-common')
|
||||
|
||||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.5.+'
|
||||
|
||||
// Servlets
|
||||
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.+'
|
||||
compile 'org.eclipse.jetty:jetty-server:9.3.+'
|
||||
compile 'org.eclipse.jetty:jetty-servlet:9.3.+'
|
||||
|
||||
// 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.+'
|
||||
|
@ -140,21 +128,6 @@ if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
|||
*===================================*/
|
||||
|
||||
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()
|
||||
|
||||
|
@ -162,13 +135,15 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
task "info" {
|
||||
doLast {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
@ -190,12 +165,12 @@ publishing {
|
|||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
url publishRepository
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
username publishUser
|
||||
password publishPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public class VotingBoothToyRun {
|
|||
|
||||
|
||||
private static List<BallotQuestion> generateChannelChoiceQuestions() {
|
||||
ArrayList<BallotQuestion> channelChoiceQuestions = new ArrayList();
|
||||
ArrayList<BallotQuestion> channelChoiceQuestions = new ArrayList<>();
|
||||
|
||||
String[] ans1 = {"Red", "Blue", "Green"};
|
||||
BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1);
|
||||
|
@ -105,7 +105,7 @@ public class VotingBoothToyRun {
|
|||
|
||||
|
||||
private static List<BallotQuestion> generateBallotQuestions() {
|
||||
ArrayList<BallotQuestion> allBallotQuestions = new ArrayList();
|
||||
ArrayList<BallotQuestion> allBallotQuestions = new ArrayList<>();
|
||||
|
||||
String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"};
|
||||
allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1));
|
||||
|
@ -222,7 +222,7 @@ public class VotingBoothToyRun {
|
|||
|
||||
|
||||
private static void generateSystemMessages() throws IOException{
|
||||
Map<String, UIElement> systemMessageMap = new HashMap();
|
||||
Map<String, UIElement> systemMessageMap = new HashMap<>();
|
||||
|
||||
systemMessageMap.put(StorageManager.WAIT_FOR_COMMIT_MESSAGE, UIElement.newBuilder()
|
||||
.setType(UIElementDataType.TEXT)
|
||||
|
|
|
@ -86,7 +86,7 @@ public class StorageManagerMockup implements StorageManager {
|
|||
logger.error("Could not read from the systemMessages file: '" + systemMessagesFilename + "'.");
|
||||
throw e;
|
||||
}
|
||||
return systemMessages.getSystemMessage();
|
||||
return systemMessages.getSystemMessageMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue