Merge branch 'master' of http://cs.idc.ac.il/rhodecode/meerkat/meerkat-java into Voter-Registry

Voter-Registry
Vladimir Eliezer Tokarev 2016-04-15 02:45:35 -07:00
commit 53fc701444
132 changed files with 10476 additions and 6638 deletions

3
.gitignore vendored
View File

@ -13,5 +13,4 @@ out
*.prefs
*.project
*.classpath
*.db
Wombat Code And Documentation Conventions
bulletin-board-server/local-instances/meerkat.db

View File

@ -1,10 +1,10 @@
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() }
}
}
}
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() }
}
}
}

View File

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

View File

@ -1,38 +1,38 @@
package meerkat.bulletinboard;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*
* This class handles bulletin client work.
* It is meant to be used in a multi-threaded environment.
*/
public abstract class BulletinClientWorker<IN> {
protected final IN payload; // Payload of the job
private int maxRetry; // Number of retries for this job; set to -1 for infinite retries
public BulletinClientWorker(IN payload, int maxRetry) {
this.payload = payload;
this.maxRetry = maxRetry;
}
public IN getPayload() {
return payload;
}
public int getMaxRetry() {
return maxRetry;
}
public void decMaxRetry(){
if (maxRetry > 0) {
maxRetry--;
}
}
public boolean isRetry(){
return (maxRetry != 0);
}
}
package meerkat.bulletinboard;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*
* This class handles bulletin client work.
* It is meant to be used in a multi-threaded environment.
*/
public abstract class BulletinClientWorker<IN> {
protected final IN payload; // Payload of the job
private int maxRetry; // Number of retries for this job; set to -1 for infinite retries
public BulletinClientWorker(IN payload, int maxRetry) {
this.payload = payload;
this.maxRetry = maxRetry;
}
public IN getPayload() {
return payload;
}
public int getMaxRetry() {
return maxRetry;
}
public void decMaxRetry(){
if (maxRetry > 0) {
maxRetry--;
}
}
public boolean isRetry(){
return (maxRetry != 0);
}
}

View File

@ -1,198 +1,198 @@
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.Timestamp;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageInputStream;
import meerkat.crypto.Digest;
import meerkat.crypto.concrete.SHA256Digest;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Voting.*;
import meerkat.rest.*;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* Implements BulletinBoardClient interface in a simple, straightforward manner
*/
public class SimpleBulletinBoardClient implements BulletinBoardClient{
protected List<String> meerkatDBs;
protected Client client;
protected Digest digest;
/**
* Stores database locations and initializes the web Client
* @param clientParams contains the data needed to access the DBs
*/
@Override
public void init(BulletinBoardClientParams clientParams) {
this.meerkatDBs = clientParams.getBulletinBoardAddressList();
client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
digest = new SHA256Digest();
}
/**
* Post message to all DBs
* Make only one try per DB.
* @param msg is the message,
* @return the message ID for later retrieval
* @throws CommunicationException
*/
@Override
public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException {
WebTarget webTarget;
Response response;
// Post message to all databases
try {
for (String db : meerkatDBs) {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
// Only consider valid responses
if (response.getStatusInfo() == Response.Status.OK
|| response.getStatusInfo() == Response.Status.CREATED) {
response.readEntity(BoolMsg.class).getValue();
}
}
} catch (Exception e) { // Occurs only when server replies with valid status but invalid data
throw new CommunicationException("Error accessing database: " + e.getMessage());
}
// Calculate the correct message ID and return it
digest.reset();
digest.update(msg.getMsg());
return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build();
}
/**
* Access each database and search for a given message ID
* Return the number of databases in which the message was found
* Only try once per DB
* Ignore communication exceptions in specific databases
* @param id is the requested message ID
* @return the number of DBs in which retrieval was successful
*/
@Override
public float getRedundancy(MessageID id) {
WebTarget webTarget;
Response response;
MessageFilterList filterList = MessageFilterList.newBuilder()
.addFilter(MessageFilter.newBuilder()
.setType(FilterType.MSG_ID)
.setId(id.getID())
.build())
.build();
float count = 0;
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
if (response.readEntity(BulletinBoardMessageList.class).getMessageCount() > 0){
count++;
}
} catch (Exception e) {}
}
return count / ((float) meerkatDBs.size());
}
/**
* Go through the DBs and try to retrieve messages according to the specified filter
* If at the operation is successful for some DB: return the results and stop iterating
* If no operation is successful: return null (NOT blank list)
* @param filterList return only messages that match the filters (null means no filtering).
* @return the list of Bulletin Board messages that are returned from a server
*/
@Override
public List<BulletinBoardMessage> readMessages(MessageFilterList filterList) {
WebTarget webTarget;
Response response;
BulletinBoardMessageList messageList;
// Replace null filter list with blank one.
if (filterList == null){
filterList = MessageFilterList.newBuilder().build();
}
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
messageList = response.readEntity(BulletinBoardMessageList.class);
if (messageList != null){
return messageList.getMessageList();
}
} catch (Exception e) {}
}
return null;
}
@Override
public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException {
WebTarget webTarget;
Response response;
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(GENERATE_SYNC_QUERY_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(generateSyncQueryParams, Constants.MEDIATYPE_PROTOBUF));
return response.readEntity(SyncQuery.class);
} catch (Exception e) {}
}
throw new CommunicationException("Could not contact any server");
}
public void close() {
client.close();
}
}
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.Timestamp;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageInputStream;
import meerkat.crypto.Digest;
import meerkat.crypto.concrete.SHA256Digest;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Voting.*;
import meerkat.rest.*;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* Implements BulletinBoardClient interface in a simple, straightforward manner
*/
public class SimpleBulletinBoardClient implements BulletinBoardClient{
protected List<String> meerkatDBs;
protected Client client;
protected Digest digest;
/**
* Stores database locations and initializes the web Client
* @param clientParams contains the data needed to access the DBs
*/
@Override
public void init(BulletinBoardClientParams clientParams) {
this.meerkatDBs = clientParams.getBulletinBoardAddressList();
client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
digest = new SHA256Digest();
}
/**
* Post message to all DBs
* Make only one try per DB.
* @param msg is the message,
* @return the message ID for later retrieval
* @throws CommunicationException
*/
@Override
public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException {
WebTarget webTarget;
Response response;
// Post message to all databases
try {
for (String db : meerkatDBs) {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
// Only consider valid responses
if (response.getStatusInfo() == Response.Status.OK
|| response.getStatusInfo() == Response.Status.CREATED) {
response.readEntity(BoolMsg.class).getValue();
}
}
} catch (Exception e) { // Occurs only when server replies with valid status but invalid data
throw new CommunicationException("Error accessing database: " + e.getMessage());
}
// Calculate the correct message ID and return it
digest.reset();
digest.update(msg.getMsg());
return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build();
}
/**
* Access each database and search for a given message ID
* Return the number of databases in which the message was found
* Only try once per DB
* Ignore communication exceptions in specific databases
* @param id is the requested message ID
* @return the number of DBs in which retrieval was successful
*/
@Override
public float getRedundancy(MessageID id) {
WebTarget webTarget;
Response response;
MessageFilterList filterList = MessageFilterList.newBuilder()
.addFilter(MessageFilter.newBuilder()
.setType(FilterType.MSG_ID)
.setId(id.getID())
.build())
.build();
float count = 0;
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
if (response.readEntity(BulletinBoardMessageList.class).getMessageCount() > 0){
count++;
}
} catch (Exception e) {}
}
return count / ((float) meerkatDBs.size());
}
/**
* Go through the DBs and try to retrieve messages according to the specified filter
* If at the operation is successful for some DB: return the results and stop iterating
* If no operation is successful: return null (NOT blank list)
* @param filterList return only messages that match the filters (null means no filtering).
* @return the list of Bulletin Board messages that are returned from a server
*/
@Override
public List<BulletinBoardMessage> readMessages(MessageFilterList filterList) {
WebTarget webTarget;
Response response;
BulletinBoardMessageList messageList;
// Replace null filter list with blank one.
if (filterList == null){
filterList = MessageFilterList.newBuilder().build();
}
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
messageList = response.readEntity(BulletinBoardMessageList.class);
if (messageList != null){
return messageList.getMessageList();
}
} catch (Exception e) {}
}
return null;
}
@Override
public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException {
WebTarget webTarget;
Response response;
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(GENERATE_SYNC_QUERY_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(generateSyncQueryParams, Constants.MEDIATYPE_PROTOBUF));
return response.readEntity(SyncQuery.class);
} catch (Exception e) {}
}
throw new CommunicationException("Could not contact any server");
}
public void close() {
client.close();
}
}

View File

@ -1,255 +1,255 @@
package meerkat.bulletinboard;
import com.google.common.util.concurrent.FutureCallback;
import com.google.protobuf.ByteString;
import meerkat.bulletinboard.workers.multiserver.*;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Voting.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* Thread-based implementation of a Async Bulletin Board Client.
* Features:
* 1. Handles tasks concurrently.
* 2. Retries submitting
*/
public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient {
// Executor service for handling jobs
private final static int JOBS_THREAD_NUM = 5;
private ExecutorService executorService;
// Per-server clients
private List<SingleServerBulletinBoardClient> clients;
private BatchDigest batchDigest;
private final static int POST_MESSAGE_RETRY_NUM = 3;
private final static int READ_MESSAGES_RETRY_NUM = 1;
private final static int GET_REDUNDANCY_RETRY_NUM = 1;
private static final int SERVER_THREADPOOL_SIZE = 5;
private static final long FAIL_DELAY = 5000;
private static final long SUBSCRIPTION_INTERVAL = 10000;
private int minAbsoluteRedundancy;
/**
* Stores database locations and initializes the web Client
* Stores the required minimum redundancy.
* Starts the Thread Pool.
* @param clientParams contains the required information
*/
@Override
public void init(BulletinBoardClientParams clientParams) {
super.init(clientParams);
batchDigest = new GenericBatchDigest(digest);
minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * (float) clientParams.getBulletinBoardAddressCount());
executorService = Executors.newFixedThreadPool(JOBS_THREAD_NUM);
clients = new ArrayList<>(clientParams.getBulletinBoardAddressCount());
for (String address : clientParams.getBulletinBoardAddressList()){
SingleServerBulletinBoardClient client =
new SingleServerBulletinBoardClient(SERVER_THREADPOOL_SIZE, FAIL_DELAY, SUBSCRIPTION_INTERVAL);
client.init(BulletinBoardClientParams.newBuilder()
.addBulletinBoardAddress(address)
.build());
clients.add(client);
}
}
/**
* Post message to all DBs
* Retry failed DBs
* @param msg is the message,
* @return the message ID for later retrieval
*/
@Override
public MessageID postMessage(BulletinBoardMessage msg, FutureCallback<Boolean> callback){
// Create job
MultiServerPostMessageWorker worker =
new MultiServerPostMessageWorker(clients, minAbsoluteRedundancy, msg, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
// Calculate the correct message ID and return it
batchDigest.reset();
batchDigest.update(msg.getMsg());
return batchDigest.digestAsMessageID();
}
@Override
public MessageID postBatch(CompleteBatch completeBatch, FutureCallback<Boolean> callback) {
// Create job
MultiServerPostBatchWorker worker =
new MultiServerPostBatchWorker(clients, minAbsoluteRedundancy, completeBatch, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
// Calculate the correct message ID and return it
batchDigest.reset();
batchDigest.update(completeBatch);
return batchDigest.digestAsMessageID();
}
@Override
public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback<Boolean> callback) {
// Create job
MultiServerBeginBatchWorker worker =
new MultiServerBeginBatchWorker(clients, minAbsoluteRedundancy, beginBatchMessage, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void postBatchData(byte[] signerId, int batchId, List<BatchData> batchDataList,
int startPosition, FutureCallback<Boolean> callback) {
BatchDataContainer batchDataContainer = new BatchDataContainer(signerId, batchId, batchDataList, startPosition);
// Create job
MultiServerPostBatchDataWorker worker =
new MultiServerPostBatchDataWorker(clients, minAbsoluteRedundancy, batchDataContainer, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void postBatchData(byte[] signerId, int batchId, List<BatchData> batchDataList, FutureCallback<Boolean> callback) {
postBatchData(signerId, batchId, batchDataList, 0, callback);
}
@Override
public void postBatchData(ByteString signerId, int batchId, List<BatchData> batchDataList,
int startPosition, FutureCallback<Boolean> callback) {
postBatchData(signerId.toByteArray(), batchId, batchDataList, startPosition, callback);
}
@Override
public void postBatchData(ByteString signerId, int batchId, List<BatchData> batchDataList, FutureCallback<Boolean> callback) {
postBatchData(signerId, batchId, batchDataList, 0, callback);
}
@Override
public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback<Boolean> callback) {
// Create job
MultiServerCloseBatchWorker worker =
new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, closeBatchMessage, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* Access each database and search for a given message ID
* Return the number of databases in which the message was found
* Only try once per DB
* Ignore communication exceptions in specific databases
*/
@Override
public void getRedundancy(MessageID id, FutureCallback<Float> callback) {
// Create job
MultiServerGetRedundancyWorker worker =
new MultiServerGetRedundancyWorker(clients, minAbsoluteRedundancy, id, GET_REDUNDANCY_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* Go through the DBs and try to retrieve messages according to the specified filter
* If at the operation is successful for some DB: return the results and stop iterating
* If no operation is successful: return null (NOT blank list)
*/
@Override
public void readMessages(MessageFilterList filterList, FutureCallback<List<BulletinBoardMessage>> callback) {
// Create job
MultiServerReadMessagesWorker worker =
new MultiServerReadMessagesWorker(clients, minAbsoluteRedundancy, filterList, READ_MESSAGES_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback<CompleteBatch> callback) {
// Create job
MultiServerReadBatchWorker worker =
new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, batchSpecificationMessage, READ_MESSAGES_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* This method is not supported by this class!
* This is because it has no meaning when considering more than one server without knowing which server will be contacted
*/
@Override
public void querySync(SyncQuery syncQuery, FutureCallback<SyncQueryResponse> callback) {
callback.onFailure(new IllegalAccessError("querySync is not supported by this class"));
}
@Override
public void close() {
super.close();
try {
for (SingleServerBulletinBoardClient client : clients){
client.close();
}
executorService.shutdown();
while (! executorService.isShutdown()) {
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
System.err.println(e.getCause() + " " + e.getMessage());
}
}
}
package meerkat.bulletinboard;
import com.google.common.util.concurrent.FutureCallback;
import com.google.protobuf.ByteString;
import meerkat.bulletinboard.workers.multiserver.*;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Voting.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* Thread-based implementation of a Async Bulletin Board Client.
* Features:
* 1. Handles tasks concurrently.
* 2. Retries submitting
*/
public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient {
// Executor service for handling jobs
private final static int JOBS_THREAD_NUM = 5;
private ExecutorService executorService;
// Per-server clients
private List<SingleServerBulletinBoardClient> clients;
private BatchDigest batchDigest;
private final static int POST_MESSAGE_RETRY_NUM = 3;
private final static int READ_MESSAGES_RETRY_NUM = 1;
private final static int GET_REDUNDANCY_RETRY_NUM = 1;
private static final int SERVER_THREADPOOL_SIZE = 5;
private static final long FAIL_DELAY = 5000;
private static final long SUBSCRIPTION_INTERVAL = 10000;
private int minAbsoluteRedundancy;
/**
* Stores database locations and initializes the web Client
* Stores the required minimum redundancy.
* Starts the Thread Pool.
* @param clientParams contains the required information
*/
@Override
public void init(BulletinBoardClientParams clientParams) {
super.init(clientParams);
batchDigest = new GenericBatchDigest(digest);
minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * (float) clientParams.getBulletinBoardAddressCount());
executorService = Executors.newFixedThreadPool(JOBS_THREAD_NUM);
clients = new ArrayList<>(clientParams.getBulletinBoardAddressCount());
for (String address : clientParams.getBulletinBoardAddressList()){
SingleServerBulletinBoardClient client =
new SingleServerBulletinBoardClient(SERVER_THREADPOOL_SIZE, FAIL_DELAY, SUBSCRIPTION_INTERVAL);
client.init(BulletinBoardClientParams.newBuilder()
.addBulletinBoardAddress(address)
.build());
clients.add(client);
}
}
/**
* Post message to all DBs
* Retry failed DBs
* @param msg is the message,
* @return the message ID for later retrieval
*/
@Override
public MessageID postMessage(BulletinBoardMessage msg, FutureCallback<Boolean> callback){
// Create job
MultiServerPostMessageWorker worker =
new MultiServerPostMessageWorker(clients, minAbsoluteRedundancy, msg, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
// Calculate the correct message ID and return it
batchDigest.reset();
batchDigest.update(msg.getMsg());
return batchDigest.digestAsMessageID();
}
@Override
public MessageID postBatch(CompleteBatch completeBatch, FutureCallback<Boolean> callback) {
// Create job
MultiServerPostBatchWorker worker =
new MultiServerPostBatchWorker(clients, minAbsoluteRedundancy, completeBatch, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
// Calculate the correct message ID and return it
batchDigest.reset();
batchDigest.update(completeBatch);
return batchDigest.digestAsMessageID();
}
@Override
public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback<Boolean> callback) {
// Create job
MultiServerBeginBatchWorker worker =
new MultiServerBeginBatchWorker(clients, minAbsoluteRedundancy, beginBatchMessage, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void postBatchData(byte[] signerId, int batchId, List<BatchData> batchDataList,
int startPosition, FutureCallback<Boolean> callback) {
BatchDataContainer batchDataContainer = new BatchDataContainer(signerId, batchId, batchDataList, startPosition);
// Create job
MultiServerPostBatchDataWorker worker =
new MultiServerPostBatchDataWorker(clients, minAbsoluteRedundancy, batchDataContainer, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void postBatchData(byte[] signerId, int batchId, List<BatchData> batchDataList, FutureCallback<Boolean> callback) {
postBatchData(signerId, batchId, batchDataList, 0, callback);
}
@Override
public void postBatchData(ByteString signerId, int batchId, List<BatchData> batchDataList,
int startPosition, FutureCallback<Boolean> callback) {
postBatchData(signerId.toByteArray(), batchId, batchDataList, startPosition, callback);
}
@Override
public void postBatchData(ByteString signerId, int batchId, List<BatchData> batchDataList, FutureCallback<Boolean> callback) {
postBatchData(signerId, batchId, batchDataList, 0, callback);
}
@Override
public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback<Boolean> callback) {
// Create job
MultiServerCloseBatchWorker worker =
new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, closeBatchMessage, POST_MESSAGE_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* Access each database and search for a given message ID
* Return the number of databases in which the message was found
* Only try once per DB
* Ignore communication exceptions in specific databases
*/
@Override
public void getRedundancy(MessageID id, FutureCallback<Float> callback) {
// Create job
MultiServerGetRedundancyWorker worker =
new MultiServerGetRedundancyWorker(clients, minAbsoluteRedundancy, id, GET_REDUNDANCY_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* Go through the DBs and try to retrieve messages according to the specified filter
* If at the operation is successful for some DB: return the results and stop iterating
* If no operation is successful: return null (NOT blank list)
*/
@Override
public void readMessages(MessageFilterList filterList, FutureCallback<List<BulletinBoardMessage>> callback) {
// Create job
MultiServerReadMessagesWorker worker =
new MultiServerReadMessagesWorker(clients, minAbsoluteRedundancy, filterList, READ_MESSAGES_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
@Override
public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback<CompleteBatch> callback) {
// Create job
MultiServerReadBatchWorker worker =
new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, batchSpecificationMessage, READ_MESSAGES_RETRY_NUM, callback);
// Submit job
executorService.submit(worker);
}
/**
* This method is not supported by this class!
* This is because it has no meaning when considering more than one server without knowing which server will be contacted
*/
@Override
public void querySync(SyncQuery syncQuery, FutureCallback<SyncQueryResponse> callback) {
callback.onFailure(new IllegalAccessError("querySync is not supported by this class"));
}
@Override
public void close() {
super.close();
try {
for (SingleServerBulletinBoardClient client : clients){
client.close();
}
executorService.shutdown();
while (! executorService.isShutdown()) {
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
System.err.println(e.getCause() + " " + e.getMessage());
}
}
}

View File

@ -0,0 +1,59 @@
package meerkat.bulletinboard.workers.singleserver;
import meerkat.bulletinboard.SingleServerWorker;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.SyncQuery;
import meerkat.protobuf.BulletinBoardAPI.SyncQueryResponse;
import meerkat.rest.Constants;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH;
import static meerkat.bulletinboard.BulletinBoardConstants.SYNC_QUERY_PATH;
/**
* Created by Arbel Deutsch Peled on 27-Dec-15.
* Tries to contact server once and perform a post operation
*/
public class SingleServerQuerySyncWorker extends SingleServerWorker<SyncQuery, SyncQueryResponse> {
public SingleServerQuerySyncWorker(String serverAddress, SyncQuery payload, int maxRetry) {
super(serverAddress, payload, maxRetry);
}
@Override
public SyncQueryResponse call() throws Exception {
Client client = clientLocal.get();
WebTarget webTarget;
Response response;
// Send request to Server
webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(SYNC_QUERY_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF));
// Retrieve answer
try {
// If a BulletinBoardMessageList is returned: the read was successful
return response.readEntity(SyncQueryResponse.class);
} catch (ProcessingException | IllegalStateException e) {
// Read failed
throw new CommunicationException("Server access failed");
}
finally {
response.close();
}
}
}

View File

@ -1 +1 @@
/bin/
/bin/

View File

@ -1,262 +1,263 @@
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
id 'org.akhikhl.gretty' version "1.2.4"
}
apply plugin: 'org.akhikhl.gretty'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
//apply plugin: 'application'
//apply plugin: 'jetty'
//mainClassName = 'SQLiteIntegrationTest'
apply plugin: 'maven-publish'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "Bulletin-board server web application"
// Your project version
version = "0.0.1"
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
dependencies {
// Meerkat common
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.+'
compile 'mysql:mysql-connector-java:5.1.+'
compile 'com.h2database:h2:1.0.+'
// 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')
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
}
test {
exclude '**/*SQLite*Test*'
exclude '**/*H2*Test*'
exclude '**/*MySQL*Test*'
exclude '**/*IntegrationTest*'
}
task myTest(type: Test) {
include '**/*MySQL*Test*'
outputs.upToDateWhen { false }
}
task h2Test(type: Test) {
include '**/*H2*Test*'
outputs.upToDateWhen { false }
}
task liteTest(type: Test) {
include '**/*SQLite*Test*'
outputs.upToDateWhen { false }
}
task dbTest(type: Test) {
include '**/*H2*Test*'
include '**/*MySQL*Test*'
include '**/*SQLite*Test*'
outputs.upToDateWhen { false }
}
task manualIntegration(type: Test) {
include '**/*IntegrationTest*'
}
task integrationTest(type: Test) {
include '**/*IntegrationTest*'
// debug = true
outputs.upToDateWhen { false }
}
gretty {
httpPort = 8081
contextPath = '/'
integrationTestTask = 'integrationTest'
loggingLevel = 'TRACE'
debugPort = 5006
}
/*==== You probably don't have to edit below this line =======*/
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
task mavenCapsule(type: MavenCapsule) {
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule) {
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
}
/*===================================
* Repositories
*===================================*/
repositories {
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
maven {
url nexusRepository
if (isSnapshot) {
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
// Use local maven repository
mavenLocal()
jcenter()
// Use 'maven central' for other dependencies.
mavenCentral()
}
task "info" << {
println "Project: ${project.name}"
println "Description: ${project.description}"
println "--------------------------"
println "GroupId: $groupId"
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
println ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
id 'org.akhikhl.gretty' version "1.2.4"
}
apply plugin: 'org.akhikhl.gretty'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
//apply plugin: 'application'
//apply plugin: 'jetty'
//mainClassName = 'SQLiteIntegrationTest'
apply plugin: 'maven-publish'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "Bulletin-board server web application"
// Your project version
version = "0.0.1"
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
dependencies {
// Meerkat common
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.+'
compile 'mysql:mysql-connector-java:5.1.+'
compile 'com.h2database:h2:1.0.+'
compile 'org.apache.commons:commons-dbcp2:2.0.+'
// 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')
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
}
test {
exclude '**/*SQLite*Test*'
exclude '**/*H2*Test*'
exclude '**/*MySQL*Test*'
exclude '**/*IntegrationTest*'
}
task myTest(type: Test) {
include '**/*MySQL*Test*'
outputs.upToDateWhen { false }
}
task h2Test(type: Test) {
include '**/*H2*Test*'
outputs.upToDateWhen { false }
}
task liteTest(type: Test) {
include '**/*SQLite*Test*'
outputs.upToDateWhen { false }
}
task dbTest(type: Test) {
include '**/*H2*Test*'
include '**/*MySQL*Test*'
include '**/*SQLite*Test*'
outputs.upToDateWhen { false }
}
task manualIntegration(type: Test) {
include '**/*IntegrationTest*'
}
task integrationTest(type: Test) {
include '**/*IntegrationTest*'
// debug = true
outputs.upToDateWhen { false }
}
gretty {
httpPort = 8081
contextPath = '/'
integrationTestTask = 'integrationTest'
loggingLevel = 'TRACE'
debugPort = 5006
}
/*==== You probably don't have to edit below this line =======*/
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
task mavenCapsule(type: MavenCapsule) {
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule) {
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
}
/*===================================
* Repositories
*===================================*/
repositories {
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
maven {
url nexusRepository
if (isSnapshot) {
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
// Use local maven repository
mavenLocal()
jcenter()
// Use 'maven central' for other dependencies.
mavenCentral()
}
task "info" << {
println "Project: ${project.name}"
println "Description: ${project.description}"
println "--------------------------"
println "GroupId: $groupId"
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
println ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}

View File

@ -1,29 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<setting name="task-tab">
<setting name="show-description" value="true"/>
</setting>
<setting name="favorites-tab"/>
<setting name="command_line-tab"/>
<setting name="setup-tab">
<setting name="setup">
<setting name="custom-gradle-executor"/>
<setting name="current-directory" value="/home/talm/proj/meerkat/bulletin-board-server"/>
<setting name="log-level" value="LIFECYCLE"/>
</setting>
</setting>
<setting name="SinglePaneUIInstance_splitter-id">
<setting name="divider_location" value="387"/>
</setting>
<setting name="main_panel">
<setting name="current-tab" value="Task Tree"/>
</setting>
<setting name="Application_window-id">
<setting name="window_x" value="306"/>
<setting name="window_y" value="1042"/>
<setting name="window_width" value="800"/>
<setting name="window_height" value="800"/>
<setting name="extended-state" value="0"/>
</setting>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<setting name="task-tab">
<setting name="show-description" value="true"/>
</setting>
<setting name="favorites-tab"/>
<setting name="command_line-tab"/>
<setting name="setup-tab">
<setting name="setup">
<setting name="custom-gradle-executor"/>
<setting name="current-directory" value="/home/talm/proj/meerkat/bulletin-board-server"/>
<setting name="log-level" value="LIFECYCLE"/>
</setting>
</setting>
<setting name="SinglePaneUIInstance_splitter-id">
<setting name="divider_location" value="387"/>
</setting>
<setting name="main_panel">
<setting name="current-tab" value="Task Tree"/>
</setting>
<setting name="Application_window-id">
<setting name="window_x" value="306"/>
<setting name="window_y" value="1042"/>
<setting name="window_width" value="800"/>
<setting name="window_height" value="800"/>
<setting name="extended-state" value="0"/>
</setting>
</root>

View File

@ -1,30 +1,30 @@
package meerkat.bulletinboard.service;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Arrays;
import java.util.List;
/**
* Created by talm on 10/11/15.
*/
public class HelloProtoBuf {
public Message sayHello() {
BulletinBoardMessage.Builder msg = BulletinBoardMessage.newBuilder();
UnsignedBulletinBoardMessage.Builder unsigned = UnsignedBulletinBoardMessage.newBuilder();
unsigned.setData(ByteString.copyFromUtf8("Hello World!"));
List<String> tags = Arrays.asList("Greetings", "FirstPrograms");
unsigned.addAllTag(tags);
msg.setMsg(unsigned);
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
sig.setData(ByteString.copyFromUtf8("deadbeef"));
msg.addSig(sig);
return msg.build();
}
}
package meerkat.bulletinboard.service;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Arrays;
import java.util.List;
/**
* Created by talm on 10/11/15.
*/
public class HelloProtoBuf {
public Message sayHello() {
BulletinBoardMessage.Builder msg = BulletinBoardMessage.newBuilder();
UnsignedBulletinBoardMessage.Builder unsigned = UnsignedBulletinBoardMessage.newBuilder();
unsigned.setData(ByteString.copyFromUtf8("Hello World!"));
List<String> tags = Arrays.asList("Greetings", "FirstPrograms");
unsigned.addAllTag(tags);
msg.setMsg(unsigned);
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
sig.setData(ByteString.copyFromUtf8("deadbeef"));
msg.addSig(sig);
return msg.build();
}
}

View File

@ -1,262 +1,266 @@
package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.h2.jdbcx.JdbcDataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
private String dbName;
public H2QueryProvider(String dbName) {
this.dbName = dbName;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return "INSERT INTO SignatureTable (EntryNum, SignerId, Signature)"
+ " SELECT DISTINCT :EntryNum AS Entry, :SignerId AS Id, :Signature AS Sig FROM UtilityTable AS Temp"
+ " WHERE NOT EXISTS"
+ " (SELECT 1 FROM SignatureTable AS SubTable WHERE SubTable.SignerId = :SignerId AND SubTable.EntryNum = :EntryNum)";
case CONNECT_TAG:
return "INSERT INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT DISTINCT TagTable.TagId, :EntryNum AS NewEntry FROM TagTable WHERE Tag = :Tag"
+ " AND NOT EXISTS (SELECT 1 FROM MsgTagTable AS SubTable WHERE SubTable.TagId = TagTable.TagId"
+ " AND SubTable.EntryNum = :EntryNum)";
case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)";
case INSERT_NEW_TAG:
return "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE"
+ " NOT EXISTS (SELECT 1 FROM TagTable AS SubTable WHERE SubTable.Tag = :Tag)";
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum >= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp" + serialString;
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp" + serialString;
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
case AFTER_TIME: // Go through
case BEFORE_TIME:
return "TIMESTAMP";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL("jdbc:h2:~/" + dbName);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, ExactTime TIMESTAMP, Msg BLOB)");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag VARCHAR(50) UNIQUE)");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
+ " FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
+ " UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)");
list.add("CREATE TABLE IF NOT EXISTS BatchTable (SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB,"
+ " UNIQUE(SignerId, BatchId, SerialNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT,"
+ " FOREIGN KEY (TagId) REFERENCES TagTable(TagId))");
list.add("CREATE INDEX IF NOT EXISTS BatchIndex ON BatchTagTable(SignerId, BatchId)");
// This is used to create a simple table with one entry.
// It is used for implementing a workaround for the missing INSERT IGNORE syntax
list.add("CREATE TABLE IF NOT EXISTS UtilityTable (Entry INT)");
list.add("INSERT INTO UtilityTable (Entry) VALUES (1)");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS UtilityTable");
list.add("DROP INDEX IF EXISTS BatchIndex");
list.add("DROP TABLE IF EXISTS BatchTagTable");
list.add("DROP TABLE IF EXISTS BatchTable");
list.add("DROP INDEX IF EXISTS SignerIdIndex");
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}
package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.apache.commons.dbcp2.BasicDataSource;
import org.h2.jdbcx.JdbcDataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
private String dbName;
public H2QueryProvider(String dbName) {
this.dbName = dbName;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return "INSERT INTO SignatureTable (EntryNum, SignerId, Signature)"
+ " SELECT DISTINCT :EntryNum AS Entry, :SignerId AS Id, :Signature AS Sig FROM UtilityTable AS Temp"
+ " WHERE NOT EXISTS"
+ " (SELECT 1 FROM SignatureTable AS SubTable WHERE SubTable.SignerId = :SignerId AND SubTable.EntryNum = :EntryNum)";
case CONNECT_TAG:
return "INSERT INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT DISTINCT TagTable.TagId, :EntryNum AS NewEntry FROM TagTable WHERE Tag = :Tag"
+ " AND NOT EXISTS (SELECT 1 FROM MsgTagTable AS SubTable WHERE SubTable.TagId = TagTable.TagId"
+ " AND SubTable.EntryNum = :EntryNum)";
case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg, ExactTime) VALUES(:MsgId,:Msg,:TimeStamp)";
case INSERT_NEW_TAG:
return "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE"
+ " NOT EXISTS (SELECT 1 FROM TagTable AS SubTable WHERE SubTable.Tag = :Tag)";
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum >= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp" + serialString;
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp" + serialString;
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
case AFTER_TIME: // Go through
case BEFORE_TIME:
return "TIMESTAMP";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:~/" + dbName);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, ExactTime TIMESTAMP, Msg BLOB)");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag VARCHAR(50) UNIQUE)");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
+ " FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
+ " UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)");
list.add("CREATE TABLE IF NOT EXISTS BatchTable (SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB,"
+ " UNIQUE(SignerId, BatchId, SerialNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT,"
+ " FOREIGN KEY (TagId) REFERENCES TagTable(TagId))");
list.add("CREATE INDEX IF NOT EXISTS BatchIndex ON BatchTagTable(SignerId, BatchId)");
// This is used to create a simple table with one entry.
// It is used for implementing a workaround for the missing INSERT IGNORE syntax
list.add("CREATE TABLE IF NOT EXISTS UtilityTable (Entry INT)");
list.add("INSERT INTO UtilityTable (Entry) VALUES (1)");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS UtilityTable");
list.add("DROP INDEX IF EXISTS BatchIndex");
list.add("DROP TABLE IF EXISTS BatchTagTable");
list.add("DROP TABLE IF EXISTS BatchTable");
list.add("DROP INDEX IF EXISTS SignerIdIndex");
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}

View File

@ -1,271 +1,273 @@
package meerkat.bulletinboard.sqlserver;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import meerkat.bulletinboard.BulletinBoardConstants;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class MySQLQueryProvider implements SQLQueryProvider {
private String dbAddress;
private int dbPort;
private String dbName;
private String username;
private String password;
public MySQLQueryProvider(String dbAddress, int dbPort, String dbName, String username, String password) {
this.dbAddress = dbAddress;
this.dbPort = dbPort;
this.dbName = dbName;
this.username = username;
this.password = password;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return MessageFormat.format(
"INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:{0}, :{1}, :{2})",
QueryType.ADD_SIGNATURE.getParamName(0),
QueryType.ADD_SIGNATURE.getParamName(1),
QueryType.ADD_SIGNATURE.getParamName(2));
case CONNECT_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, :{0} AS EntryNum FROM TagTable WHERE Tag = :{1}",
QueryType.CONNECT_TAG.getParamName(0),
QueryType.CONNECT_TAG.getParamName(1));
case FIND_MSG_ID:
return MessageFormat.format(
"SELECT EntryNum From MsgTable WHERE MsgId = :{0}",
QueryType.FIND_MSG_ID.getParamName(0));
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return MessageFormat.format(
"SELECT Signature FROM SignatureTable WHERE EntryNum = :{0}",
QueryType.GET_SIGNATURES.getParamName(0));
case INSERT_MSG:
return MessageFormat.format(
"INSERT INTO MsgTable (MsgId, ExactTime, Msg) VALUES(:{0}, :{1}, :{2})",
QueryType.INSERT_MSG.getParamName(0),
QueryType.INSERT_MSG.getParamName(1),
QueryType.INSERT_MSG.getParamName(2));
case INSERT_NEW_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO TagTable(Tag) VALUES (:{0})",
QueryType.INSERT_NEW_TAG.getParamName(0));
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum >= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp";
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
case AFTER_TIME: // Go through
case BEFORE_TIME:
return "TIMESTAMP";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerName(dbAddress);
dataSource.setPort(dbPort);
dataSource.setDatabaseName(dbName);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setAllowMultiQueries(true);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY,"
+ " MsgId TINYBLOB, ExactTime TIMESTAMP, Msg BLOB, UNIQUE(MsgId(50)))");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag VARCHAR(50), UNIQUE(Tag))");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
+ " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
+ " CONSTRAINT UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB,"
+ " INDEX(SignerId(32)), CONSTRAINT Unique_Signature UNIQUE(SignerId(32), EntryNum),"
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTable (SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB,"
+ " CONSTRAINT Unique_Batch UNIQUE(SignerId(32), BatchId, SerialNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT,"
+ " INDEX(SignerId(32), BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS BatchTagTable");
list.add("DROP TABLE IF EXISTS BatchTable");
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}
package meerkat.bulletinboard.sqlserver;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import meerkat.bulletinboard.BulletinBoardConstants;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class MySQLQueryProvider implements SQLQueryProvider {
private String dbAddress;
private int dbPort;
private String dbName;
private String username;
private String password;
public MySQLQueryProvider(String dbAddress, int dbPort, String dbName, String username, String password) {
this.dbAddress = dbAddress;
this.dbPort = dbPort;
this.dbName = dbName;
this.username = username;
this.password = password;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return MessageFormat.format(
"INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:{0}, :{1}, :{2})",
QueryType.ADD_SIGNATURE.getParamName(0),
QueryType.ADD_SIGNATURE.getParamName(1),
QueryType.ADD_SIGNATURE.getParamName(2));
case CONNECT_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, :{0} AS EntryNum FROM TagTable WHERE Tag = :{1}",
QueryType.CONNECT_TAG.getParamName(0),
QueryType.CONNECT_TAG.getParamName(1));
case FIND_MSG_ID:
return MessageFormat.format(
"SELECT EntryNum From MsgTable WHERE MsgId = :{0}",
QueryType.FIND_MSG_ID.getParamName(0));
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return MessageFormat.format(
"SELECT Signature FROM SignatureTable WHERE EntryNum = :{0}",
QueryType.GET_SIGNATURES.getParamName(0));
case INSERT_MSG:
return MessageFormat.format(
"INSERT INTO MsgTable (MsgId, ExactTime, Msg) VALUES(:{0}, :{1}, :{2})",
QueryType.INSERT_MSG.getParamName(0),
QueryType.INSERT_MSG.getParamName(1),
QueryType.INSERT_MSG.getParamName(2));
case INSERT_NEW_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO TagTable(Tag) VALUES (:{0})",
QueryType.INSERT_NEW_TAG.getParamName(0));
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum >= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp";
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
case AFTER_TIME: // Go through
case BEFORE_TIME:
return "TIMESTAMP";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://" + dbAddress + ":" + dbPort + "/" + dbName);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY,"
+ " MsgId TINYBLOB, ExactTime TIMESTAMP, Msg BLOB, UNIQUE(MsgId(50)))");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag VARCHAR(50), UNIQUE(Tag))");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
+ " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
+ " CONSTRAINT UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB,"
+ " INDEX(SignerId(32)), CONSTRAINT Unique_Signature UNIQUE(SignerId(32), EntryNum),"
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTable (SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB,"
+ " CONSTRAINT Unique_Batch UNIQUE(SignerId(32), BatchId, SerialNum))");
list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT,"
+ " INDEX(SignerId(32), BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS BatchTagTable");
list.add("DROP TABLE IF EXISTS BatchTable");
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}

View File

@ -1,233 +1,233 @@
package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.*;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
String dbName;
public SQLiteQueryProvider(String dbName) {
this.dbName = dbName;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum,:SignerId,:Signature)";
case CONNECT_TAG:
return "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag";
case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)";
case INSERT_NEW_TAG:
return "INSERT OR IGNORE INTO TagTable(Tag) VALUES (:Tag)";
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT = :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp";
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INTEGER";
case MSG_ID: // Go through
case SIGNER_ID:
return "BLOB";
case TAG:
return "VARCHAR";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl("jdbc:sqlite:" + dbName);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum)"
+ " REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INTEGER, SignerId BLOB, Signature BLOB,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), UNIQUE(SignerId, EntryNum))");
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP INDEX IF EXISTS SignerIndex");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}
package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.*;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 09-Dec-15.
*/
public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
String dbName;
public SQLiteQueryProvider(String dbName) {
this.dbName = dbName;
}
@Override
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) {
case ADD_SIGNATURE:
return "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum,:SignerId,:Signature)";
case CONNECT_TAG:
return "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag";
case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case COUNT_MESSAGES:
return "SELECT COUNT(MsgTable.EntryNum) FROM MsgTable";
case GET_MESSAGE_STUBS:
return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable";
case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)";
case INSERT_NEW_TAG:
return "INSERT OR IGNORE INTO TagTable(Tag) VALUES (:Tag)";
case GET_LAST_MESSAGE_ENTRY:
return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable";
case GET_BATCH_MESSAGE_ENTRY:
return MessageFormat.format(
"SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"
+ " INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum"
+ " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum"
+ " INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId"
+ " WHERE SignatureTable.SignerId = :{0}"
+ " AND TagTable.Tag = :{1}",
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0),
QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1));
case GET_BATCH_MESSAGE_DATA:
return MessageFormat.format(
"SELECT Data FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}"
+ " ORDER BY SerialNum ASC",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case REMOVE_BATCH_TAGS:
return MessageFormat.format(
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
}
@Override
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) {
case EXACT_ENTRY:
return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MIN_ENTRY:
return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MAX_MESSAGES:
return "LIMIT = :Limit" + serialString;
case MSG_ID:
return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG:
return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
case BEFORE_TIME:
return "MsgTable.ExactTime <= :TimeStamp";
case AFTER_TIME:
return "MsgTable.ExactTime >= :TimeStamp";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MIN_ENTRY: // Go through
case MAX_MESSAGES:
return "INTEGER";
case MSG_ID: // Go through
case SIGNER_ID:
return "BLOB";
case TAG:
return "VARCHAR";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl("jdbc:sqlite:" + dbName);
return dataSource;
}
@Override
public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>();
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum)"
+ " REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INTEGER, SignerId BLOB, Signature BLOB,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), UNIQUE(SignerId, EntryNum))");
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
return list;
}
@Override
public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP INDEX IF EXISTS SignerIndex");
list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable");
list.add("DROP TABLE IF EXISTS MsgTable");
return list;
}
}

View File

@ -1,18 +1,18 @@
package meerkat.bulletinboard.sqlserver.mappers;
import meerkat.protobuf.BulletinBoardAPI.MessageID;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class LongMapper implements RowMapper<Long> {
@Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
}
package meerkat.bulletinboard.sqlserver.mappers;
import meerkat.protobuf.BulletinBoardAPI.MessageID;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class LongMapper implements RowMapper<Long> {
@Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
}

View File

@ -1,32 +1,32 @@
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class MessageMapper implements RowMapper<BulletinBoardMessage.Builder> {
@Override
public BulletinBoardMessage.Builder mapRow(ResultSet rs, int rowNum) throws SQLException {
BulletinBoardMessage.Builder builder = BulletinBoardMessage.newBuilder();
try {
builder.setEntryNum(rs.getLong(1))
.setMsg(UnsignedBulletinBoardMessage.parseFrom(rs.getBytes(2)));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
return builder;
}
}
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class MessageMapper implements RowMapper<BulletinBoardMessage.Builder> {
@Override
public BulletinBoardMessage.Builder mapRow(ResultSet rs, int rowNum) throws SQLException {
BulletinBoardMessage.Builder builder = BulletinBoardMessage.newBuilder();
try {
builder.setEntryNum(rs.getLong(1))
.setMsg(UnsignedBulletinBoardMessage.parseFrom(rs.getBytes(2)));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
return builder;
}
}

View File

@ -1,28 +1,28 @@
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.Crypto.Signature;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class SignatureMapper implements RowMapper<Signature> {
@Override
public Signature mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
return Signature.parseFrom(rs.getBytes(1));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
}
}
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.Crypto.Signature;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class SignatureMapper implements RowMapper<Signature> {
@Override
public Signature mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
return Signature.parseFrom(rs.getBytes(1));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
}
}

View File

@ -1,265 +1,265 @@
package meerkat.bulletinboard.webapp;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.H2QueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageOutputStream;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import static meerkat.rest.Constants.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
/**
* An implementation of the BulletinBoardServer which functions as a WebApp
*/
@Path(BULLETIN_BOARD_SERVER_PATH)
public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{
private static final String BULLETIN_BOARD_ATTRIBUTE_NAME = "bulletinBoard";
@Context ServletContext servletContext;
BulletinBoardServer bulletinBoard;
/**
* This is the servlet init method.
*/
public void init(){
bulletinBoard = (BulletinBoardServer) servletContext.getAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME);
}
/**
* This is the BulletinBoard init method.
*/
@Override
public void init(String meerkatDB) throws CommunicationException {
bulletinBoard.init(meerkatDB);
}
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
String dbType = servletContext.getInitParameter("dbType");
String dbName = servletContext.getInitParameter("dbName");
if ("SQLite".equals(dbType)){
bulletinBoard = new BulletinBoardSQLServer(new SQLiteQueryProvider(dbName));
} else if ("H2".equals(dbType)) {
bulletinBoard = new BulletinBoardSQLServer(new H2QueryProvider(dbName));
} else if ("MySQL".equals(dbType)) {
String dbAddress = servletContext.getInitParameter("dbAddress");
int dbPort = Integer.parseInt(servletContext.getInitParameter("dbPort"));
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
bulletinBoard = new BulletinBoardSQLServer(new MySQLQueryProvider(dbAddress,dbPort,dbName,username,password));
}
try {
init(dbName);
servletContext.setAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME, bulletinBoard);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
}
}
@Path(POST_MESSAGE_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
init();
return bulletinBoard.postMessage(msg);
}
@Override
public void readMessages(MessageFilterList filterList, MessageOutputStream<BulletinBoardMessage> out) throws CommunicationException {
init();
bulletinBoard.readMessages(filterList, out);
}
@Path(READ_MESSAGES_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
/**
* Wrapper for the readMessages method which streams the output into the response
*/
public StreamingOutput readMessages(final MessageFilterList filterList) {
return new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
MessageOutputStream<BulletinBoardMessage> out = new MessageOutputStream<>(output);
try {
init();
bulletinBoard.readMessages(filterList, out);
} catch (CommunicationException e) {
//TODO: Log
out.writeMessage(null);
}
}
};
}
@Path(BEGIN_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg beginBatch(BeginBatchMessage message) {
try {
init();
return bulletinBoard.beginBatch(message);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(POST_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postBatchMessage(BatchMessage batchMessage) {
try {
init();
return bulletinBoard.postBatchMessage(batchMessage);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(CLOSE_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg closeBatchMessage(CloseBatchMessage message) {
try {
init();
return bulletinBoard.closeBatchMessage(message);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Override
public void readBatch(BatchSpecificationMessage message, MessageOutputStream<BatchData> out) {
try {
init();
bulletinBoard.readBatch(message, out);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
}
}
@Path(GENERATE_SYNC_QUERY_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException {
try {
init();
return bulletinBoard.generateSyncQuery(generateSyncQueryParams);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(READ_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
/**
* Wrapper for the readBatch method which streams the output into the response
*/
public StreamingOutput readBatch(final BatchSpecificationMessage message) {
return new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
MessageOutputStream<BatchData> out = new MessageOutputStream<>(output);
try {
init();
bulletinBoard.readBatch(message, out);
} catch (CommunicationException e) {
//TODO: Log
out.writeMessage(null);
}
}
};
}
@Path(SYNC_QUERY_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException {
try{
init();
return bulletinBoard.querySync(syncQuery);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
}
@Override
public void close(){
try {
bulletinBoard.close();
} catch (CommunicationException e) {
System.err.println(e.getMessage());
}
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String test() {
return "This BulletinBoard is up and running!\n Please consult the API documents to perform queries.";
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
bulletinBoard = (BulletinBoardServer) servletContext.getAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME);
close();
}
}
package meerkat.bulletinboard.webapp;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.H2QueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageOutputStream;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import static meerkat.rest.Constants.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
/**
* An implementation of the BulletinBoardServer which functions as a WebApp
*/
@Path(BULLETIN_BOARD_SERVER_PATH)
public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{
private static final String BULLETIN_BOARD_ATTRIBUTE_NAME = "bulletinBoard";
@Context ServletContext servletContext;
BulletinBoardServer bulletinBoard;
/**
* This is the servlet init method.
*/
public void init(){
bulletinBoard = (BulletinBoardServer) servletContext.getAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME);
}
/**
* This is the BulletinBoard init method.
*/
@Override
public void init(String meerkatDB) throws CommunicationException {
bulletinBoard.init(meerkatDB);
}
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
String dbType = servletContext.getInitParameter("dbType");
String dbName = servletContext.getInitParameter("dbName");
if ("SQLite".equals(dbType)){
bulletinBoard = new BulletinBoardSQLServer(new SQLiteQueryProvider(dbName));
} else if ("H2".equals(dbType)) {
bulletinBoard = new BulletinBoardSQLServer(new H2QueryProvider(dbName));
} else if ("MySQL".equals(dbType)) {
String dbAddress = servletContext.getInitParameter("dbAddress");
int dbPort = Integer.parseInt(servletContext.getInitParameter("dbPort"));
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
bulletinBoard = new BulletinBoardSQLServer(new MySQLQueryProvider(dbAddress,dbPort,dbName,username,password));
}
try {
init(dbName);
servletContext.setAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME, bulletinBoard);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
}
}
@Path(POST_MESSAGE_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
init();
return bulletinBoard.postMessage(msg);
}
@Override
public void readMessages(MessageFilterList filterList, MessageOutputStream<BulletinBoardMessage> out) throws CommunicationException {
init();
bulletinBoard.readMessages(filterList, out);
}
@Path(READ_MESSAGES_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
/**
* Wrapper for the readMessages method which streams the output into the response
*/
public StreamingOutput readMessages(final MessageFilterList filterList) {
return new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
MessageOutputStream<BulletinBoardMessage> out = new MessageOutputStream<>(output);
try {
init();
bulletinBoard.readMessages(filterList, out);
} catch (CommunicationException e) {
//TODO: Log
out.writeMessage(null);
}
}
};
}
@Path(BEGIN_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg beginBatch(BeginBatchMessage message) {
try {
init();
return bulletinBoard.beginBatch(message);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(POST_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postBatchMessage(BatchMessage batchMessage) {
try {
init();
return bulletinBoard.postBatchMessage(batchMessage);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(CLOSE_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg closeBatchMessage(CloseBatchMessage message) {
try {
init();
return bulletinBoard.closeBatchMessage(message);
} catch (CommunicationException e) {
System.err.println(e.getMessage());
return null;
}
}
@Override
public void readBatch(BatchSpecificationMessage message, MessageOutputStream<BatchData> out) {
try {
init();
bulletinBoard.readBatch(message, out);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
}
}
@Path(GENERATE_SYNC_QUERY_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException {
try {
init();
return bulletinBoard.generateSyncQuery(generateSyncQueryParams);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
}
@Path(READ_BATCH_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
/**
* Wrapper for the readBatch method which streams the output into the response
*/
public StreamingOutput readBatch(final BatchSpecificationMessage message) {
return new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
MessageOutputStream<BatchData> out = new MessageOutputStream<>(output);
try {
init();
bulletinBoard.readBatch(message, out);
} catch (CommunicationException e) {
//TODO: Log
out.writeMessage(null);
}
}
};
}
@Path(SYNC_QUERY_PATH)
@POST
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException {
try{
init();
return bulletinBoard.querySync(syncQuery);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
}
@Override
public void close(){
try {
bulletinBoard.close();
} catch (CommunicationException e) {
System.err.println(e.getMessage());
}
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String test() {
return "This BulletinBoard is up and running!\n Please consult the API documents to perform queries.";
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
bulletinBoard = (BulletinBoardServer) servletContext.getAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME);
close();
}
}

View File

@ -1,50 +1,50 @@
package meerkat.bulletinboard.webapp;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.bulletinboard.service.HelloProtoBuf;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/proto")
public class HelloProtoWebApp {
private HelloProtoBuf helloProtoBuf;
@PostConstruct
public void init() {
helloProtoBuf = new HelloProtoBuf();
}
@GET
@Produces(Constants.MEDIATYPE_PROTOBUF)
public Message hello() {
byte[] b1 = { (byte) 1, (byte) 2, (byte) 3, (byte) 4 };
byte[] b2 = { (byte) 11, (byte) 12, (byte) 13, (byte) 14 };
byte[] b3 = {(byte) 21, (byte)22, (byte) 23, (byte) 24};
Message msg;
if (helloProtoBuf != null) {
msg = helloProtoBuf.sayHello();
} else {
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Signature")
.addTag("Trustee")
.setData(ByteString.copyFrom(b1)).build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3)).build())
.build();
}
return msg;
}
}
package meerkat.bulletinboard.webapp;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.bulletinboard.service.HelloProtoBuf;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/proto")
public class HelloProtoWebApp {
private HelloProtoBuf helloProtoBuf;
@PostConstruct
public void init() {
helloProtoBuf = new HelloProtoBuf();
}
@GET
@Produces(Constants.MEDIATYPE_PROTOBUF)
public Message hello() {
byte[] b1 = { (byte) 1, (byte) 2, (byte) 3, (byte) 4 };
byte[] b2 = { (byte) 11, (byte) 12, (byte) 13, (byte) 14 };
byte[] b3 = {(byte) 21, (byte)22, (byte) 23, (byte) 24};
Message msg;
if (helloProtoBuf != null) {
msg = helloProtoBuf.sayHello();
} else {
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Signature")
.addTag("Trustee")
.setData(ByteString.copyFrom(b1)).build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3)).build())
.build();
}
return msg;
}
}

View File

@ -1,9 +1,9 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message Boolean {
bool value = 1;
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message Boolean {
bool value = 1;
}

View File

@ -1,12 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
<Arg>none</Arg>
</Call>
</Configure>

View File

@ -1,38 +1,38 @@
<web-app>
<servlet>
<servlet-name>Jersey Hello World</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>meerkat</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Hello World</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>dbAddress</param-name>
<param-value>localhost</param-value></context-param>
<context-param>
<param-name>dbPort</param-name>
<param-value>3306</param-value></context-param>
<context-param>
<param-name>dbName</param-name>
<param-value>meerkat</param-value></context-param>
<context-param>
<param-name>username</param-name>
<param-value>arbel</param-value></context-param>
<context-param>
<param-name>password</param-name>
<param-value>mypass</param-value></context-param>
<context-param>
<param-name>dbType</param-name>
<param-value>H2</param-value></context-param>
<listener>
<listener-class>meerkat.bulletinboard.webapp.BulletinBoardWebApp</listener-class>
</listener>
</web-app>
<web-app>
<servlet>
<servlet-name>Jersey Hello World</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>meerkat</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Hello World</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>dbAddress</param-name>
<param-value>localhost</param-value></context-param>
<context-param>
<param-name>dbPort</param-name>
<param-value>3306</param-value></context-param>
<context-param>
<param-name>dbName</param-name>
<param-value>meerkat</param-value></context-param>
<context-param>
<param-name>username</param-name>
<param-value>arbel</param-value></context-param>
<context-param>
<param-name>password</param-name>
<param-value>mypass</param-value></context-param>
<context-param>
<param-name>dbType</param-name>
<param-value>H2</param-value></context-param>
<listener>
<listener-class>meerkat.bulletinboard.webapp.BulletinBoardWebApp</listener-class>
</listener>
</web-app>

View File

@ -1,149 +1,149 @@
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.TextFormat;
import com.google.protobuf.Timestamp;
import meerkat.comm.MessageInputStream;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.util.List;
public class BulletinBoardSQLServerIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String DEFAULT_BASE_URL = "http://localhost:8081";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
Client client;
@Before
public void setup() throws Exception {
System.err.println("Registering client");
client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
}
@Test
public void testPost() throws Exception {
byte[] b1 = {(byte) 1, (byte) 2, (byte) 3, (byte) 4};
byte[] b2 = {(byte) 11, (byte) 12, (byte) 13, (byte) 14};
byte[] b3 = {(byte) 21, (byte) 22, (byte) 23, (byte) 24};
byte[] b4 = {(byte) 4, (byte) 5, (byte) 100, (byte) -50, (byte) 0};
Timestamp t1 = Timestamp.newBuilder()
.setSeconds(8276482)
.setNanos(4314)
.build();
Timestamp t2 = Timestamp.newBuilder()
.setSeconds(987591)
.setNanos(1513)
.build();
WebTarget webTarget;
Response response;
BoolMsg bool;
BulletinBoardMessage msg;
MessageFilterList filterList;
List<BulletinBoardMessage> msgList;
// Test writing mechanism
System.err.println("******** Testing: " + POST_MESSAGE_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
System.err.println(webTarget.getUri());
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Signature")
.addTag("Trustee")
.setData(ByteString.copyFrom(b1))
.setTimestamp(t1)
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3))
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b3))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Vote")
.addTag("Trustee")
.setData(ByteString.copyFrom(b4))
.setTimestamp(t2)
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b4))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
// Test reading mechanism
System.err.println("******** Testing: " + READ_MESSAGES_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
filterList = MessageFilterList.newBuilder()
.addFilter(
MessageFilter.newBuilder()
.setType(FilterType.TAG)
.setTag("Vote")
.build()
)
.build();
InputStream in = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF), InputStream.class);
MessageInputStream<BulletinBoardMessage> inputStream =
MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BulletinBoardMessage.class);
msgList = inputStream.asList();
System.err.println("List size: " + msgList.size());
System.err.println("This is the list:");
for (BulletinBoardMessage message : msgList) {
System.err.println(TextFormat.printToString(message));
}
assert msgList.size() == 1;
}
}
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.TextFormat;
import com.google.protobuf.Timestamp;
import meerkat.comm.MessageInputStream;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.util.List;
public class BulletinBoardSQLServerIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String DEFAULT_BASE_URL = "http://localhost:8081";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
Client client;
@Before
public void setup() throws Exception {
System.err.println("Registering client");
client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
}
@Test
public void testPost() throws Exception {
byte[] b1 = {(byte) 1, (byte) 2, (byte) 3, (byte) 4};
byte[] b2 = {(byte) 11, (byte) 12, (byte) 13, (byte) 14};
byte[] b3 = {(byte) 21, (byte) 22, (byte) 23, (byte) 24};
byte[] b4 = {(byte) 4, (byte) 5, (byte) 100, (byte) -50, (byte) 0};
Timestamp t1 = Timestamp.newBuilder()
.setSeconds(8276482)
.setNanos(4314)
.build();
Timestamp t2 = Timestamp.newBuilder()
.setSeconds(987591)
.setNanos(1513)
.build();
WebTarget webTarget;
Response response;
BoolMsg bool;
BulletinBoardMessage msg;
MessageFilterList filterList;
List<BulletinBoardMessage> msgList;
// Test writing mechanism
System.err.println("******** Testing: " + POST_MESSAGE_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
System.err.println(webTarget.getUri());
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Signature")
.addTag("Trustee")
.setData(ByteString.copyFrom(b1))
.setTimestamp(t1)
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.DSA)
.setData(ByteString.copyFrom(b2))
.setSignerId(ByteString.copyFrom(b3))
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b3))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
msg = BulletinBoardMessage.newBuilder()
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addTag("Vote")
.addTag("Trustee")
.setData(ByteString.copyFrom(b4))
.setTimestamp(t2)
.build())
.addSig(Signature.newBuilder()
.setType(SignatureType.ECDSA)
.setData(ByteString.copyFrom(b4))
.setSignerId(ByteString.copyFrom(b2))
.build())
.build();
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
System.err.println(response);
bool = response.readEntity(BoolMsg.class);
assert bool.getValue();
// Test reading mechanism
System.err.println("******** Testing: " + READ_MESSAGES_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
filterList = MessageFilterList.newBuilder()
.addFilter(
MessageFilter.newBuilder()
.setType(FilterType.TAG)
.setTag("Vote")
.build()
)
.build();
InputStream in = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF), InputStream.class);
MessageInputStream<BulletinBoardMessage> inputStream =
MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BulletinBoardMessage.class);
msgList = inputStream.asList();
System.err.println("List size: " + msgList.size());
System.err.println("This is the list:");
for (BulletinBoardMessage message : msgList) {
System.err.println(TextFormat.printToString(message));
}
assert msgList.size() == 1;
}
}

View File

@ -1,155 +1,165 @@
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.bulletinboard.sqlserver.H2QueryProvider;
import meerkat.comm.CommunicationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.Result;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.sql.*;
import java.util.List;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class H2BulletinBoardServerTest {
private final String dbName = "meerkatTest";
private GenericBulletinBoardServerTest serverTest;
private SQLQueryProvider queryProvider;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
queryProvider = new H2QueryProvider(dbName);
try {
Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
for (String deletionQuery : deletionQueries) {
stmt.execute(deletionQuery);
}
} catch (SQLException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void testBatchPostAfterClose() {
try{
serverTest.testBatchPostAfterClose();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testBatch() {
final int BATCH_NUM = 20;
try{
for (int i = 0 ; i < BATCH_NUM ; i++) {
serverTest.testPostBatch();
}
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testReadBatch();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After
public void close() {
System.err.println("Starting to close H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.bulletinboard.sqlserver.H2QueryProvider;
import meerkat.comm.CommunicationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.Result;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.sql.*;
import java.util.List;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class H2BulletinBoardServerTest {
private final String dbName = "meerkatTest";
private GenericBulletinBoardServerTest serverTest;
private SQLQueryProvider queryProvider;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
queryProvider = new H2QueryProvider(dbName);
try {
Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
for (String deletionQuery : deletionQueries) {
stmt.execute(deletionQuery);
}
} catch (SQLException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void testBatchPostAfterClose() {
try{
serverTest.testBatchPostAfterClose();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testBatch() {
final int BATCH_NUM = 20;
try{
for (int i = 0 ; i < BATCH_NUM ; i++) {
serverTest.testPostBatch();
}
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testReadBatch();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testSyncQuery() {
try {
serverTest.testSyncQuery();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After
public void close() {
System.err.println("Starting to close H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing H2BulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}

View File

@ -1,42 +1,42 @@
package meerkat.bulletinboard;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import org.junit.Test;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Created by talm on 10/11/15.
*/
public class HelloProtoIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String DEFAULT_BASE_URL = "http://localhost:8081/";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
private static String HELLO_URL = "proto";
@Test
public void testHello() throws Exception {
Client client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
WebTarget webTarget = client.target(BASE_URL).path(HELLO_URL);
BulletinBoardMessage response = webTarget.request(Constants.MEDIATYPE_PROTOBUF)
.get(BulletinBoardMessage.class);
System.out.println(response.getMsg().getData());
assertThat(response.getMsg().getData().toStringUtf8(), is("Hello World!"));
assertThat(response.getMsg().getTagCount(), is(2));
assertThat(response.getMsg().getTag(0), is("Greetings"));
assertThat(response.getMsg().getTag(1), is("FirstPrograms"));
}
}
package meerkat.bulletinboard;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import org.junit.Test;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Created by talm on 10/11/15.
*/
public class HelloProtoIntegrationTest {
private static String PROP_GETTY_URL = "gretty.httpBaseURI";
private static String DEFAULT_BASE_URL = "http://localhost:8081/";
private static String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL);
private static String HELLO_URL = "proto";
@Test
public void testHello() throws Exception {
Client client = ClientBuilder.newClient();
client.register(ProtobufMessageBodyReader.class);
client.register(ProtobufMessageBodyWriter.class);
WebTarget webTarget = client.target(BASE_URL).path(HELLO_URL);
BulletinBoardMessage response = webTarget.request(Constants.MEDIATYPE_PROTOBUF)
.get(BulletinBoardMessage.class);
System.out.println(response.getMsg().getData());
assertThat(response.getMsg().getData().toStringUtf8(), is("Hello World!"));
assertThat(response.getMsg().getTagCount(), is(2));
assertThat(response.getMsg().getTag(0), is("Greetings"));
assertThat(response.getMsg().getTag(1), is("FirstPrograms"));
}
}

View File

@ -1,172 +1,172 @@
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.comm.CommunicationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.InvocationTargetException;
import java.security.SignatureException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class MySQLBulletinBoardServerTest {
private final String dbAddress = "localhost";
private final int dbPort = 3306;
private final String dbName = "meerkat";
private final String username = "arbel";
private final String password = "mypass";
private GenericBulletinBoardServerTest serverTest;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
SQLQueryProvider queryProvider = new MySQLQueryProvider(dbAddress,dbPort,dbName,username,password);
try {
Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
for (String deletionQuery : deletionQueries) {
stmt.execute(deletionQuery);
}
} catch (SQLException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void testBatchPostAfterClose() {
try{
serverTest.testBatchPostAfterClose();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testBatch() {
final int BATCH_NUM = 20;
try{
for (int i = 0 ; i < BATCH_NUM ; i++) {
serverTest.testPostBatch();
}
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testReadBatch();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testSyncQuery() {
try {
serverTest.testSyncQuery();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After
public void close() {
System.err.println("Starting to close MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.comm.CommunicationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.InvocationTargetException;
import java.security.SignatureException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class MySQLBulletinBoardServerTest {
private final String dbAddress = "localhost";
private final int dbPort = 3306;
private final String dbName = "meerkat";
private final String username = "arbel";
private final String password = "mypass";
private GenericBulletinBoardServerTest serverTest;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
SQLQueryProvider queryProvider = new MySQLQueryProvider(dbAddress,dbPort,dbName,username,password);
try {
Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
for (String deletionQuery : deletionQueries) {
stmt.execute(deletionQuery);
}
} catch (SQLException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void testBatchPostAfterClose() {
try{
serverTest.testBatchPostAfterClose();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testBatch() {
final int BATCH_NUM = 20;
try{
for (int i = 0 ; i < BATCH_NUM ; i++) {
serverTest.testPostBatch();
}
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testReadBatch();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testSyncQuery() {
try {
serverTest.testSyncQuery();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After
public void close() {
System.err.println("Starting to close MySQLBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing MySQLBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}

View File

@ -1,106 +1,106 @@
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.security.*;
import java.security.cert.CertificateException;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class SQLiteBulletinBoardServerTest{
private String testFilename = "SQLiteDBTest.db";
private GenericBulletinBoardServerTest serverTest;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
File old = new File(testFilename);
old.delete();
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(new SQLiteQueryProvider(testFilename));
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@After
public void close() {
System.err.println("Starting to close SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}
package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.security.*;
import java.security.cert.CertificateException;
import static org.junit.Assert.fail;
/**
* Created by Arbel Deutsch Peled on 07-Dec-15.
*/
public class SQLiteBulletinBoardServerTest{
private String testFilename = "SQLiteDBTest.db";
private GenericBulletinBoardServerTest serverTest;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
@Before
public void init(){
System.err.println("Starting to initialize SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
File old = new File(testFilename);
old.delete();
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(new SQLiteQueryProvider(testFilename));
try {
bulletinBoardServer.init("");
} catch (CommunicationException e) {
System.err.println(e.getMessage());
fail(e.getMessage());
return;
}
serverTest = new GenericBulletinBoardServerTest();
try {
serverTest.init(bulletinBoardServer);
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@Test
public void bulkTest() {
System.err.println("Starting bulkTest of SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
try {
serverTest.testInsert();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testSimpleTagAndSignature();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testEnhancedTagsAndSignatures();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished bulkTest of SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
@After
public void close() {
System.err.println("Starting to close SQLiteBulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime();
serverTest.close();
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished closing SQLiteBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
}
}

View File

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

View File

@ -0,0 +1,47 @@
package meerkat.crypto.dkg.comm;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.comm.Channel;
import meerkat.protobuf.Comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by Tzlil on 2/14/2016.
*
* an implementation of ReceiverCallback
*/
public abstract class MessageHandler implements Channel.ReceiverCallback {
final Logger logger = LoggerFactory.getLogger(getClass());
/**
* fixed value for broadcasting
*/
public static final int BROADCAST = 0;
/**
* Handle a broadcast (or unicast) message.
* If the message is invalid, the handler can throw an {@link InvalidProtocolBufferException}, in which
* case the message will simply be ignored.
* @param envelope
*/
public abstract void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException;
/**
* Was this broadcastMessage was received by broadcast channel
* @param broadcastMessage
* @return broadcastMessage user destination == BROADCAST
*/
public boolean isBroadcast(Comm.BroadcastMessage broadcastMessage){
return broadcastMessage.getDestination() == BROADCAST;
}
@Override
public void receiveMessage(Comm.BroadcastMessage envelope) {
try {
handleMessage(envelope);
} catch (InvalidProtocolBufferException e) {
logger.warn("Received invalid protocol buffer from channel", e);
}
}
}

View File

@ -0,0 +1,36 @@
package meerkat.crypto.dkg.comm;
import meerkat.protobuf.DKG;
/**
* Created by talm on 12/04/16.
*/
public class MessageUtils {
public static DKG.Payload createMessage(DKG.Payload.Type type) {
return DKG.Payload.newBuilder().setType(type).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.ShareMessage share) {
return DKG.Payload.newBuilder().setType(type).setShare(share).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.ShareMessage.Builder share) {
return DKG.Payload.newBuilder().setType(type).setShare(share).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.IDMessage id) {
return DKG.Payload.newBuilder().setType(type).setId(id).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.IDMessage.Builder id) {
return DKG.Payload.newBuilder().setType(type).setId(id).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.CommitmentMessage commitment) {
return DKG.Payload.newBuilder().setType(type).setCommitment(commitment).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.CommitmentMessage.Builder commitment) {
return DKG.Payload.newBuilder().setType(type).setCommitment(commitment).build();
}
}

View File

@ -0,0 +1,40 @@
package meerkat.crypto.dkg.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Created by Tzlil on 3/14/2016.
*
* contains all relevant information on specific party during
* the run of Joint Feldamn protocol
*/
public class Party<T> {
public final int id;
public Polynomial.Point share;
public ArrayList<T> commitments;
public boolean doneFlag;
public Protocol.ComplaintState[] complaints;
public boolean aborted;
/**
*
* @param id party identifier - 1 <= id <= n
* @param n number of parties in current run protocol
* @param t protocol's threshold
*/
public Party(int id, int n, int t) {
this.id = id;
this.share = null;
this.doneFlag = false;
this.complaints = new Protocol.ComplaintState[n];
Arrays.fill(this.complaints, Protocol.ComplaintState.OK);
this.commitments = new ArrayList<T>(t + 1);
for (int i = 0; i <= t ; i++){
commitments.add(null);
}
this.aborted = false;
}
}

View File

@ -0,0 +1,368 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import com.google.protobuf.ByteString;
import meerkat.protobuf.DKG;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.util.ByteEncoder;
import java.math.BigInteger;
import java.util.*;
import static meerkat.crypto.dkg.comm.MessageUtils.*;
/**
* Created by Tzlil on 3/14/2016.
*
* an implementation of JointFeldman distributed key generation protocol.
*
* allows set of n parties to generate random key with threshold t.
*/
public class Protocol<T> extends VerifiableSecretSharing<T> {
public enum ComplaintState {
/**
* No complaints, no response required at this point.
*/
OK,
/**
* Party received complaint, waiting for response from party
*/
Waiting,
/**
* Party gave invalid answer to conplaint.
*/
Disqualified,
/**
* Party received complaint, gave valid answer.
*/
NonDisqualified
}
/**
* My share id.
*/
protected final int id;
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
private Party<T>[] parties;
/**
* communication object
*/
protected Channel channel;
/**
* Encode/Decode group elements
*/
protected final ByteEncoder<T> encoder;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
* @param group
* @param q a large prime dividing group order.
* @param g a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
* @param encoder Encode/Decode group elements (of type T) to/from byte array
*/
public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, Group<T> group, int id, ByteEncoder<T> encoder) {
super(t, n, zi, random, q, g,group);
this.id = id;
this.parties = new Party[n];
for (int i = 1; i <= n ; i++){
this.parties[i - 1] = new Party(i,n,t);
}
this.parties[id - 1].share = getShare(id);
this.encoder = encoder;
}
/**
* setter
* @param channel
*/
public void setChannel(Channel channel){
this.channel = channel;
}
/**
* setter
* @param parties
*/
protected void setParties(Party[] parties){
this.parties = parties;
}
/**
* getter
* @return
*/
protected Party[] getParties(){
return parties;
}
/**
* stage1.1 according to the protocol
* Pi broadcasts Aik for k = 0,...,t.
*/
public void broadcastCommitments(){
broadcastCommitments(commitmentsArrayList);
}
/**
* pack commitments as messages and broadcast them
* @param commitments
*/
public void broadcastCommitments(ArrayList<T> commitments){
DKG.CommitmentMessage commitmentMessage;
for (int k = 0; k <= t ; k++){
commitmentMessage = DKG.CommitmentMessage.newBuilder()
.setCommitment(ByteString.copyFrom(encoder.encode(commitments.get(k))))
.setK(k)
.build();
channel.broadcastMessage(createMessage(DKG.Payload.Type.COMMITMENT, commitmentMessage));
}
}
/**
* Send channel j her secret share (of my polynomial)
* @param j
*/
public void sendSecret(int j){
ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray());
channel.sendMessage(j, createMessage(DKG.Payload.Type.SHARE,
DKG.ShareMessage.newBuilder()
.setI(id)
.setJ(j)
.setShare(secret)
));
}
/**
* stage1.2 according to the protocol
* Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj.
*/
public void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
sendSecret(j);
}
}
}
/**
*
* @param i
* @return computeVerificationValue(j,parties[i - 1].commitments,group) == g ^ parties[i - 1].share mod q
*/
public boolean isValidShare(int i){
Party<T> party = parties[i - 1];
synchronized (parties[i - 1]) {
return isValidShare(party.share, party.commitments, id);
}
}
/**
* @param share
* @param commitments
* @param j
* @return computeVerificationValue(j,commitments,group) == g ^ secret.y mod q
*/
public boolean isValidShare(Polynomial.Point share, ArrayList<T> commitments, int j){
try{
T v = computeVerificationValue(j,commitments,group);
return group.multiply(g,share.y).equals(v);
}
catch (NullPointerException e){
return false;
}
}
/**
* stage2 according to the protocol
* Pj verifies all the shares he received (using isValidShare)
* if check fails for an index i, Pj broadcasts a complaint against Pi.
*/
public void broadcastComplaints(){
for (int i = 1; i <= n ; i++ ){
if(i != id && !isValidShare(i)) {
broadcastComplaint(i);
}
}
}
/**
* create a complaint message against i and broadcast it
* @param i
*/
private void broadcastComplaint(int i){
//message = new Message(Type.Complaint, j)
DKG.IDMessage complaint = DKG.IDMessage.newBuilder()
.setId(i)
.build();
channel.broadcastMessage(createMessage(DKG.Payload.Type.COMPLAINT, complaint));
}
/**
* create an answer message for j and broadcast it
* @param j
*/
public void broadcastComplaintAnswer(int j){
channel.broadcastMessage(createMessage(DKG.Payload.Type.ANSWER, DKG.ShareMessage.newBuilder()
.setI(id)
.setJ(j)
.setShare(ByteString.copyFrom(getShare(j).y.toByteArray()))));
}
/**
* stage3.1 according to the protocol
* if more than t players complain against a player Pi he is disqualified.
*/
public void answerAllComplainingPlayers(){
ComplaintState[] complaints = parties[id - 1].complaints;
for (int i = 1; i <= n; i++) {
switch (complaints[i - 1]) {
case Waiting:
broadcastComplaintAnswer(i);
break;
default:
break;
}
}
}
/**
* stage3.2 according to the protocol
* if any of the revealed shares fails the verification test, player Pi is disqualified.
* set QUAL to be the set of non-disqualified players.
*/
public Set<Integer> calcQUAL(){
Set<Integer> QUAL = new HashSet<Integer>();
boolean nonDisqualified;
int counter;
for (int i = 1; i <= n; i++) {
synchronized (parties[i - 1]) {
ComplaintState[] complaints = parties[i - 1].complaints;
nonDisqualified = true;
counter = 0;
for (int j = 1; j <= n; j++) {
switch (complaints[j - 1]) {
case OK:
break;
case NonDisqualified:
counter++;
break;
default:
nonDisqualified = false;
break;
}
if (!nonDisqualified)
break;
}
if (nonDisqualified && counter <= t) {
QUAL.add(i);
}
}
}
return QUAL;
}
/**
* compute Y, the commitment to the final public key (includes only qualifying set)
* stage4.1 according to the protocol
* public value y is computed as y = multiplication of yi mod p for i in QUAL
*/
public T calcY(Set<Integer> QUAL){
T y = group.zero();
for (int i : QUAL) {
synchronized (parties[i - 1]) {
y = group.add(y, parties[i - 1].commitments.get(0));
}
}
return y;
}
/**
* stage4.2 according to the protocol
* public verification values are computed as Ak = multiplication
* of Aik mod p for i in QUAL for k = 0,...,t
*/
public ArrayList<T> calcCommitments(Set<Integer> QUAL){
ArrayList<T> commitments = new ArrayList<T>(t+1);
T value;
for (int k = 0; k <= t; k++){
value = group.zero();
for (int i : QUAL) {
synchronized (parties[i - 1]) {
value = group.add(value, parties[i - 1].commitments.get(k));
}
}
commitments.add(k,value);
}
return commitments;
}
/**
* stage4.3 according to the protocol
* Pj sets is share of the share as xj = sum of Sij mod q for i in QUAL
*/
public Polynomial.Point calcShare(Set<Integer> QUAL){
BigInteger xj = BigInteger.ZERO;
for (int i : QUAL) {
synchronized (parties[i - 1]) {
xj = xj.add(parties[i - 1].share.y);
}
}
return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q));
}
/**
* decode commitment from arr
* @param arr
* @return
*/
public T decodeCommitment(byte[] arr){
return encoder.decode(arr);
}
/**
* getter
* @return id
*/
public int getId() {
return id;
}
/**
* getter
* @return channel
*/
public Channel getChannel() {
return channel;
}
/**
* getter
* @return encoder
*/
public ByteEncoder<T> getEncoder() {
return encoder;
}
}

View File

@ -0,0 +1,588 @@
package meerkat.crypto.dkg.feldman;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.TextFormat;
import meerkat.comm.Channel;
import meerkat.crypto.dkg.comm.MessageHandler;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import com.google.protobuf.ByteString;
import meerkat.protobuf.Comm;
import meerkat.protobuf.DKG;
import org.factcenter.qilin.primitives.Group;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import static meerkat.crypto.dkg.comm.MessageUtils.createMessage;
/**
* Created by Tzlil on 3/14/2016.
*
* implementation of joint feldman protocol user.
*
* according to the protocol, each user run feldman verifiable secret sharing
* as a dealer.
*
* by the end of run(), each party in QUAL has his own share of the generated random key.
* this key can be recover by any subset of QUAL of size at least t + 1.
*/
public class User<T> implements Runnable {
final Logger logger = LoggerFactory.getLogger(getClass());
/**
* joint feldman protocol object
*/
protected final Protocol<T> dkg;
/**
* a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
protected final T g;
/**
* cyclic group contains g.
*/
protected final Group<T> group;
/**
* user id
*/
protected final int id;
/**
* threshold
*/
protected final int t;
/**
* number of shares
*/
protected final int n;
/**
* channel object
*/
protected final Channel channel; //
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
protected final Party[] parties;
/**
* set of all non-disqualified parties
*/
protected Set<Integer> QUAL;
/**
* my own share of the generated random key.
*/
protected Polynomial.Point share;
/**
* public verification values
*/
protected ArrayList<T> commitments;
/**
* public value,
* y = g ^ key
*/
protected T y;
protected BlockingQueue<Comm.BroadcastMessage> receiveQueue;
/**
* constructor
* @param dkg joint feldman protocol object
* @param channel channel object
*/
public User(Protocol<T> dkg, Channel channel) {
this.dkg = dkg;
this.g = dkg.getGenerator();
this.group = dkg.getGroup();
this.n = dkg.getN();
this.t = dkg.getT();
this.id = dkg.getId();
this.channel = channel;
dkg.setChannel(channel);
registerReceiverCallback();
this.parties = dkg.getParties();
this.QUAL = null;
this.commitments = null;
this.share = null;
this.y = null;
this.receiveQueue = new LinkedBlockingDeque<>();
}
/**
* create MessageHandler and register it as ReceiverCallback
*/
protected void registerReceiverCallback() {
channel.registerReceiverCallback(new meerkat.crypto.dkg.comm.MessageHandler() {
@Override
public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException {
receiveQueue.add(envelope);
}
});
// this.messageHandler = new MessageHandler();
// channel.registerReceiverCallback(messageHandler);
}
/**
* Wait for at least one message to arrive, then handle any messages currently in the queue
*/
protected void waitAndHandleReceivedMessages() {
Comm.BroadcastMessage msg = null;
while (!stop && msg == null) {
try {
msg = receiveQueue.take();
} catch (InterruptedException e) {
// Possibly stop
}
}
while (!stop && msg != null) {
try {
handleMessage(msg);
} catch (InvalidProtocolBufferException e) {
logger.warn("Received invalid message: {}", TextFormat.printToString(msg));
}
msg = receiveQueue.poll();
}
}
/**
* stage1 according to the protocol
* 1. Pi broadcasts Aik for k = 0,...,t.
* 2. Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj.
*/
protected void stage1() {
dkg.broadcastCommitments();
dkg.sendSecrets();
}
/**
* Check if all shares and commitments have arrived from other parties
*/
protected boolean isStageOneCompleted() {
for (int i = 0 ; i < n ; i++) {
if (!parties[i].aborted) {
if (parties[i].share == null)
return false;
for (int k = 0 ; k <= t ; k++) {
if (parties[i].commitments.get(k) == null)
return false;
}
}
}
return true;
}
protected void waitUntilStageOneCompleted() {
while (!stop && !isStageOneCompleted())
waitAndHandleReceivedMessages();
}
protected boolean isStageTwoCompleted() {
for (int i = 0 ; i < n ; i++) {
if (!parties[i].aborted && !parties[i].doneFlag)
return false;
}
return true;
}
/**
* stage2 according to the protocol
* Pj verifies all the shares he received
* if check fails for an index i, Pj broadcasts a complaint against Pi.
* Pj broadcasts done message at the end of this stage
*/
protected void stage2() {
dkg.broadcastComplaints();
//broadcast done message after all complaints
channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE));
}
/**
* wait until all other parties done complaining by receiving done message
*/
protected void waitUntilStageTwoCompleted(){
while (!stop && !isStageTwoCompleted())
waitAndHandleReceivedMessages();
}
protected boolean haveReceivedAllStage3ComplaintAnswers() {
for (int i = 0; i < n; i++) {
if (parties[i].aborted)
continue;
for (int j = 0; j < n; j++) {
if (parties[i].complaints[j].equals(Protocol.ComplaintState.Waiting))
return false;
}
}
return true;
}
/**
* stage3 according to the protocol
* 1. if more than t players complain against a player Pi he is disqualified.
* otherwise Pi broadcasts the share Sij for each complaining player Pj.
* 2. if any of the revealed shares fails the verification test, player Pi is disqualified.
* set QUAL to be the set of non-disqualified players.
*/
protected void stage3(){
dkg.answerAllComplainingPlayers();
// wait until there is no complaint waiting for answer
while (!stop && !haveReceivedAllStage3ComplaintAnswers())
waitAndHandleReceivedMessages();
this.QUAL = dkg.calcQUAL();
}
/**
* stage4 according to the protocol
* 1. public value y is computed as y = multiplication of yi mod p for i in QUAL
* 2. public verification values are computed as Ak = multiplication of Aik mod p for i in QUAL for k = 0,...,t
* 3. Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL
*/
protected void stage4(){
this.y = dkg.calcY(QUAL);
this.commitments = dkg.calcCommitments(QUAL);
this.share = dkg.calcShare(QUAL);
}
@Override
public void run() {
this.runThread = Thread.currentThread();
// For debugging
String previousName = runThread.getName();
runThread.setName(getClass().getName() +":" + getID());
try {
stage1();
waitUntilStageOneCompleted();
if (stop) return;
stage2();
waitUntilStageTwoCompleted();
if (stop) return;
stage3();
if (stop) return;
stage4();
} finally {
runThread.setName(previousName);
}
}
/**
* current thread in the main loop
*/
protected Thread runThread;
/**
* flag indicates if there was request to stop the current run of the protocol
*/
protected boolean stop = false;
/**
* Request the current run loop to exit gracefully
*/
public void stop() {
try {
stop = true;
runThread.interrupt();
}catch (Exception e){
//do nothing
}
}
/**
* getter
* @return commitments
*/
public ArrayList<T> getCommitments() {
return commitments;
}
/**
* getter
* @return g
*/
public T getGenerator() {
return g;
}
/**
* getter
* @return group
*/
public Group<T> getGroup() {
return group;
}
/**
* getter
* @return share
*/
public Polynomial.Point getShare() {
return share;
}
/**
* getter
* @return id
*/
public int getID() {
return id;
}
/**
* getter
* @return n
*/
public int getN() {
return n;
}
/**
* getter
* @return t
*/
public int getT() {
return t;
}
/**
* getter
* @return y
*/
public T getPublicValue() {
return y;
}
/**
* getter
* @return QUAL
*/
public Set<Integer> getQUAL() {
return QUAL;
}
/**
* getter
* @return channel
*/
public Channel getChannel() {
return channel;
}
/**
* commitment message is valid if:
* 1. it was received in broadcast chanel
* 2. the sender didn't sent this commitment before
*/
protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKG.CommitmentMessage commitmentMessage){
int i = sender - 1;
int k = commitmentMessage.getK();
return isBroadcast && parties[i].commitments.get(k) == null;
}
/**
* secret message is valid if:
* 1. it was received in private chanel
* 2. the sender didn't sent secret message before
* 3. secret.i == i
* 4. secret.j == id
*/
protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){
int i = secretMessage.getI();
int j = secretMessage.getJ();
if(sender != i || isBroadcast)
return false;
else
return parties[i - 1].share == null && j == id;
}
/**
* done message is valid if:
* 1. it was received in broadcast chanel
* 2. the sender didn't sent done message before
*/
protected boolean isValidDoneMessage(int sender, boolean isBroadcast){
return isBroadcast && !parties[sender - 1].doneFlag;
}
/**
* complaint message is valid if:
* 1. it was received in broadcast chanel
* 2. the sender didn't complained against id before
*/
protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){
int i = sender;
int j = complaintMessage.getId();
assert(i > 0);
assert(j > 0);
assert(i <= parties.length);
assert(j <= parties[i-1].complaints.length);
return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK);
}
/**
* answer message is valid if:
* 1. it was received in broadcast chanel
* 2. secret.i == i
* 3. 1 <= secret.j <= n
* 4. it is marked that j complained against i and i didn't received
*/
protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){
int i = secretMessage.getI();
int j = secretMessage.getJ();
if(sender != i || !isBroadcast)
return false;
else
return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(Protocol.ComplaintState.Waiting);
}
public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException {
int sender = envelope.getSender();
boolean isBroadcast = !envelope.getIsPrivate();
DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload());
logger.debug("handling Message: Dst={}, Src={}, [{}]",
envelope.getDestination(), envelope.getSender(), TextFormat.printToString(msg));
switch (msg.getType()) {
case COMMITMENT:
/**
* saves the commitment
*/
assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.COMMITMENT;
DKG.CommitmentMessage commitmentMessage = msg.getCommitment();
if (isValidCommitmentMessage(sender, isBroadcast, commitmentMessage)) {
int i = sender - 1;
int k = commitmentMessage.getK();
parties[i].commitments.set(k, extractCommitment(commitmentMessage));
}
break;
case SHARE:
/**
* saves the secret
*/
assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE;
DKG.ShareMessage secretMessage = msg.getShare();
if(isValidSecretMessage(sender,isBroadcast,secretMessage)) {
int i = secretMessage.getI();
Polynomial.Point secret = extractShare(id,secretMessage.getShare());
parties[i - 1].share = secret;
}
break;
case DONE:
/**
* marks that the sender was finished sending all his complaints
*/
if(isValidDoneMessage(sender,isBroadcast)) {
parties[sender - 1].doneFlag = true;
}
break;
case COMPLAINT:
/**
* marks that the sender was complained against id
*/
if (msg.getPayloadDataCase() != DKG.Payload.PayloadDataCase.ID) {
logger.error("User {} Expecting ID message, got from SRC={} msg {}", getID(), envelope.getSender(), TextFormat.printToString(msg));
assert (msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.ID);
}
DKG.IDMessage complaintMessage = msg.getId();
if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){
int i = sender;
int j = complaintMessage.getId();
parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting;
}
break;
case ANSWER:
/**
* if the secret is valid, marks the complaint as NonDisqualified
* else marks it as Disqualified
* in case that the complainer is id ( j == id ), saves the secret
*/
assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE;
secretMessage = msg.getShare();
if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) {
int i = secretMessage.getI();
int j = secretMessage.getJ();
Polynomial.Point secret = extractShare(j,secretMessage.getShare());
if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) {
parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.NonDisqualified;
} else {
parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.Disqualified;
}
if (j == id) {
parties[i - 1].share = secret;
}
}
break;
case ABORT:
/**
* marks that the sender was aborted
*/
parties[sender - 1].aborted = true;
break;
default:
logger.error("Bad message: SRC={}, DST={}, Payload={}", envelope.getSender(), envelope.getDestination(), TextFormat.printToString(msg));
break;
}
}
/**
* extract share value from ByteString
* @param i
* @param share
* @return new Point (i,share)
*/
public Polynomial.Point extractShare(int i, ByteString share){
BigInteger x = BigInteger.valueOf(i);
BigInteger y = new BigInteger(share.toByteArray());
return new Polynomial.Point(x,y);
}
/**
*
* @param commitmentMessage
* @return
*/
public T extractCommitment(DKG.CommitmentMessage commitmentMessage){
return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray());
}
}

View File

@ -0,0 +1,28 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Tzlil on 3/16/2016.
*
* an extension of DistributedKeyGenerationParty
* contains all relevant information on specific party during
* the run of the safe protocol
*/
public class Party<T> extends meerkat.crypto.dkg.feldman.Party<T> {
public Polynomial.Point shareT;
public boolean ysDoneFlag;
public ArrayList<T> verifiableValues;
public Set<Polynomial.Point> recoverSharesSet;
public Party(int id, int n, int t) {
super(id, n, t);
this.shareT = null;
this.ysDoneFlag = false;
this.verifiableValues = new ArrayList<T>(this.commitments);
this.recoverSharesSet = new HashSet<Polynomial.Point>();
}
}

View File

@ -0,0 +1,165 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.crypto.dkg.comm.MessageUtils;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import com.google.protobuf.ByteString;
import meerkat.protobuf.DKG;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.util.ByteEncoder;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/16/2016.
* TODO: comments
* TODO: put Channel (ChannelImpl) in constructor
*/
public class Protocol<T> extends meerkat.crypto.dkg.feldman.Protocol<T> {
private VerifiableSecretSharing<T> maskingShares;
private final T h;
private Party<T>[] parties;
public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, T h, Group<T> group, int id, ByteEncoder<T> byteEncoder) {
super(t, n, zi, random, q, g, group, id,byteEncoder);
this.h = h;
BigInteger r = new BigInteger(q.bitLength(),random).mod(q);
this.maskingShares = new VerifiableSecretSharing(t,n,r,random,q,h,group);
this.parties = new Party[n];
for (int i = 1; i <= n ; i++){
this.parties[i - 1] = new Party(i,n,t);
}
this.parties[id - 1].share = getShare(id);
this.parties[id - 1].shareT = maskingShares.getShare(id);
super.setParties(parties);
}
protected Party[] getParties(){
return parties;
}
protected void setParties(Party[] parties) {
super.setParties(parties);
this.parties = parties;
}
@Override
public void sendSecret(int j) {
Polynomial.Point secret = getShare(j);
Polynomial.Point secretT = maskingShares.getShare(j);
DKG.ShareMessage doubleSecretMessage = createShareMessage(id,j,secret,secretT);
// TODO: Change SHARE to SHARE
channel.sendMessage(j, MessageUtils.createMessage(DKG.Payload.Type.SHARE, doubleSecretMessage));
}
@Override
public boolean isValidShare(int i){
Party party = parties[i - 1];
return isValidShare(party.share, party.shareT, party.verifiableValues, id);
}
/**
* test if share, shareT are valid with respect to verificationValues
* @param share
* @param shareT
* @param verificationValues
* @param j
* @return computeVerificationValue(j,verificationValues,group) == (g ^ share.y) * (h ^ shareT.y) mod q
*/
public boolean isValidShare(Polynomial.Point share, Polynomial.Point shareT, ArrayList<T> verificationValues, int j){
try {
T v = computeVerificationValue(j, verificationValues, group);
T exp = group.add(group.multiply(g, share.y), group.multiply(h, shareT.y));
return exp.equals(v);
}
catch (NullPointerException e){
return false;
}
}
/**
* create complaint message against i and broadcast it
* @param share
* @param shareT
* @param i
*/
private void broadcastComplaint(Polynomial.Point share, Polynomial.Point shareT, int i){
DKG.ShareMessage complaint = createShareMessage(i,id,share,shareT);
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.COMPLAINT, complaint));
}
/**
* stage4.3 according to the protocol
* if check fails for index i, Pj
*/
public void computeAndBroadcastComplaints(Set<Integer> QUAL){
Party party;
for (int i : QUAL) {
party = parties[i - 1];
if (i != id) {
if (!super.isValidShare(party.share, party.commitments, id)) {
broadcastComplaint(party.share, party.shareT, i);
}
}
}
}
/**
* compute verification values and broadcast them
* verificationValues[k] = g ^ commitments [k] * h ^ maskingShares.commitments [k]
*/
public void computeAndBroadcastVerificationValues(){
ArrayList<T> verificationValues = new ArrayList<T>(t+1);
ArrayList<T> hBaseCommitments = maskingShares.getCommitmentsArrayList();
for (int k = 0 ; k <= t ; k++){
verificationValues.add(k,group.add(commitmentsArrayList.get(k),hBaseCommitments.get(k)));
}
broadcastCommitments(verificationValues);
}
/**
* pack share, shareT i,j to createShareMessage
* @param i
* @param j
* @param share
* @param shareT
* @return
*/
private DKG.ShareMessage createShareMessage(int i, int j, Polynomial.Point share, Polynomial.Point shareT){
DKG.ShareMessage ShareMessage = DKG.ShareMessage.newBuilder()
.setI(i)
.setJ(j)
.setShare(ByteString.copyFrom(share.y.toByteArray()))
.setShareT(ByteString.copyFrom(shareT.y.toByteArray()))
.build();
return ShareMessage;
}
@Override
public void broadcastComplaintAnswer(int j) {
DKG.ShareMessage answer = createShareMessage(id,j,getShare(j)
, maskingShares.getShare(j));
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER, answer));
}
public void broadcastAnswer(Polynomial.Point secret, Polynomial.Point secretT, int i){
DKG.ShareMessage complaint = createShareMessage(i,id,secret,secretT);
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER,complaint));
}
/**
* getter
* @return h
*/
public T getH() {
return h;
}
}

View File

@ -0,0 +1,359 @@
package meerkat.crypto.dkg.gjkr;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.protobuf.Comm;
import meerkat.protobuf.DKG;
import java.math.BigInteger;
import java.util.ArrayList;
import static meerkat.crypto.dkg.comm.MessageUtils.*;
/**
* Created by Tzlil on 3/16/2016.
* <p/>
* implementation of gjkr protocol user.
* <p/>
* this protocol extends joint Feldman protocol by splitting the protocol to commitment stage (stages 1,2,3)
* and revealing stage (stage 4).
* <p/>
* as in joint Feldman, each party in QUAL has his own share of the generated random key.
* this key can be recover by any subset of QUAL of size at least t + 1.
*/
public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
protected Party<T>[] parties;
/**
* gjkr secure protocol object
*/
protected final Protocol<T> sdkg;
boolean isStage4;
/**
* constructor
*
* @param sdkg gjkr protocol object
* @param channel channel object
*/
public User(Protocol<T> sdkg, Channel channel) {
super(sdkg, channel);
this.sdkg = sdkg;
this.parties = sdkg.getParties();
}
/**
* stage1 according to the protocol
* 1. Pi broadcasts Cik=Aik*Bik for k = 0,...,t.
* 2. Pi computes the shares Sij,Sij' for j = 1,...,n and sends Sij,Sij' secretly to Pj.
*/
@Override
protected void stage1() {
sdkg.computeAndBroadcastVerificationValues();
sdkg.sendSecrets();
}
@Override
protected void waitUntilStageOneCompleted() {
super.waitUntilStageOneCompleted();
// save the received commitments as verification values
ArrayList<T> temp;
for (int i = 0; i < n; i++) {
temp = parties[i].verifiableValues;
parties[i].verifiableValues = parties[i].commitments;
parties[i].commitments = temp;
}
}
/**
* stage2 according to the protocol
* Pj verifies all the shares,sharesT he received
* if check fails for an index i, Pj broadcasts a complaint against Pi.
* Pj broadcasts done message at the end of this stage
*/
@Override
protected void stage2() {
sdkg.broadcastComplaints();
//broadcast done message after all complaints
channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE));
}
/**
* Check if all non-aborting qualified parties have sent commitments.
* @return
*/
protected boolean haveAllQualPartiesCommitted() {
for (int i : QUAL) {
if (parties[i - 1].aborted)
continue;
for (int k = 0; k <= t; k++) {
if (parties[i - 1].commitments.get(k) == null)
return false;
}
}
return true;
}
/**
* Check if all non-aborting qualified parties sent a done message
* @return
*/
protected boolean areAllQualPartiesDone() {
for (int i : QUAL) {
if (parties[i - 1].aborted)
continue;
for (int k = 0; k <= t; k++) {
if (!parties[i - 1].ysDoneFlag)
return false;
}
}
return true;
}
/**
* Check if at least t + 1 secrets were received foreach i in QUAL that aborted
* @return
*/
protected boolean haveReceivedEnoughSecretShares() {
for (int i : QUAL) {
if (parties[i - 1].aborted && parties[i - 1].recoverSharesSet.size() <= t)
return false;
}
return true;
}
/**
* broadcast commitments and recover parties information if necessary
*/
private void resolveQualifyingPublicKey() {
sdkg.broadcastCommitments();
// wait until all parties in QUAL broadcast their commitments or aborted
while (!stop && !haveAllQualPartiesCommitted())
waitAndHandleReceivedMessages();
if (stop)
return;
sdkg.computeAndBroadcastComplaints(QUAL);
//broadcast done message after all complaints
channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE));
// wait until all parties in QUAL done or aborted
while (!stop && !areAllQualPartiesDone())
waitAndHandleReceivedMessages();
if (stop)
return;
// broadcast i private secret foreach i in QUAL that aborted
for (int i : QUAL) {
if (parties[i - 1].aborted) {
sdkg.broadcastAnswer(parties[i - 1].share, parties[i - 1].shareT, i);
}
}
// wait until at least t + 1 secrets will received foreach i in QUAL that aborted
while (!stop && !haveReceivedEnoughSecretShares())
waitAndHandleReceivedMessages();
if (stop)
return;
Arithmetic<BigInteger> arithmetic = new Fp(sdkg.getQ());
// restore necessary information
for (int i = 0; i < n; i++) {
if (parties[i].recoverSharesSet.isEmpty()) {
continue;
}
Polynomial.Point[] shares = new Polynomial.Point[t + 1];
int j = 0;
for (Polynomial.Point share : parties[i].recoverSharesSet) {
shares[j++] = share;
if (j >= shares.length) {
break;
}
}
Polynomial polynomial = SecretSharing.recoverPolynomial(shares, arithmetic);
BigInteger[] coefficients = polynomial.getCoefficients();
for (int k = 0; k <= t; k++) {
parties[i].commitments.add(k, group.multiply(g, coefficients[k]));
}
parties[i].share = new Polynomial.Point(BigInteger.valueOf(id), polynomial);
}
}
/**
* notifies message handler and message handler that stage 4 was started
*/
protected void setStage4() {
isStage4 = true;
}
@Override
protected void stage4() {
setStage4();
resolveQualifyingPublicKey();
if (stop) return;
super.stage4();
}
/**
* if !isStage4 as super, with extension to double secret message
* else answer message is valid if:
* 1. it was received in broadcast chanel
* 2. secret.j == sender
* 3. QUAL contains i and j
*/
protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage doubleSecretMessage) {
if (!isStage4) {
return super.isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage);
} else {
int i = doubleSecretMessage.getI();
int j = doubleSecretMessage.getJ();
return isBroadcast && j == sender && parties[i - 1].aborted && !parties[j - 1].aborted
&& QUAL.contains(i) && QUAL.contains(j);
}
}
/**
* as in super with respect to protocol stage
*/
@Override
protected boolean isValidDoneMessage(int sender, boolean isBroadcast) {
if (!isStage4) {
return super.isValidDoneMessage(sender, isBroadcast);
} else {
return isBroadcast && !parties[sender - 1].ysDoneFlag;
}
}
/**
* use only in stage4
* complaint message is valid if:
* 1. it was received in broadcast chanel
* 2. secret.j == sender
* 3. QUAL contains i and j
*/
protected boolean isValidComplaintMessage(int sender, boolean isBroadcast,
DKG.ShareMessage complaintMessage) {
int i = complaintMessage.getI();
int j = complaintMessage.getJ();
return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j);
}
@Override
public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException {
int sender = envelope.getSender();
boolean isBroadcast = !envelope.getIsPrivate();
DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload());
switch (msg.getType()) {
case SHARE:
/**
* as in super, with extension to double secret message
*/
DKG.ShareMessage doubleSecretMessage = msg.getShare();
if (isValidSecretMessage(sender, isBroadcast, doubleSecretMessage)) {
int i = doubleSecretMessage.getI();
synchronized (parties[i - 1]) {
parties[i - 1].share = extractShare(id, doubleSecretMessage.getShare());
parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getShareT());
parties[i - 1].notify();
}
}
break;
case ANSWER:
/**
* if !isStage4 as super, with extension to double secret message
* else saves secret
*/
assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE;
doubleSecretMessage = msg.getShare();
if (isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage)) {
int i = doubleSecretMessage.getI();
int j = doubleSecretMessage.getJ();
Polynomial.Point secret = extractShare(j, doubleSecretMessage.getShare());
Polynomial.Point secretT = extractShare(j, doubleSecretMessage.getShareT());
synchronized (parties[i - 1]) {
if (!isStage4) {
if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) {
parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.NonDisqualified;
} else {
parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.Disqualified;
}
if (j == id) {
parties[i - 1].share = secret;
parties[i - 1].shareT = secretT;
}
} else if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j)) {
parties[i - 1].recoverSharesSet.add(secret);
}
parties[i - 1].notify();
}
}
break;
case DONE:
/**
* as in super with respect to protocol state
*/
if (!isStage4)
super.handleMessage(envelope);
else {
if (isValidDoneMessage(sender, isBroadcast)) {
synchronized (parties[sender - 1]) {
parties[sender - 1].ysDoneFlag = true;
parties[sender - 1].notify();
}
}
}
break;
case COMPLAINT:
/**
* if !isStage4 as in super
* else if secret,secretT are valid with respect to verifiableValues but
* secret is not valid with respect to commitments then
* marks i as aborted
*/
if (!isStage4) {
super.handleMessage(envelope);
} else {
assert (msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE);
DKG.ShareMessage ysComplaintMessage = msg.getShare();
if (isValidComplaintMessage(sender, isBroadcast, ysComplaintMessage)) {
int i = ysComplaintMessage.getI();
int j = ysComplaintMessage.getJ();
Polynomial.Point secret = extractShare(i, ysComplaintMessage.getShare());
Polynomial.Point secretT = extractShare(i, ysComplaintMessage.getShareT());
if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j)
&& !dkg.isValidShare(secret, parties[i - 1].commitments, j)) {
synchronized (parties[i - 1]) {
parties[i - 1].aborted = true;
parties[i - 1].notify();
}
}
}
}
break;
default:
super.handleMessage(envelope);
break;
}
}
}

View File

@ -0,0 +1,117 @@
package meerkat.crypto.secretsharing.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import org.factcenter.qilin.primitives.Group;
import java.util.ArrayList;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*
* an implementation of Feldman's verifiable secret sharing scheme.
*
* allows trusted dealer to share a key x among n parties.
*
*/
public class VerifiableSecretSharing<T> extends SecretSharing {
/**
* cyclic group contains g.
*/
protected final Group<T> group;
/**
* a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
protected final T g;
/**
* commitments to polynomial coefficients.
* commitments[k] = g ^ coefficients[k] (group operation)
*/
protected final ArrayList<T> commitmentsArrayList;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
* @param group
* @param q a large prime dividing group order.
* @param g a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
public VerifiableSecretSharing(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, Group<T> group) {
super(t, n, zi, random,q);
this.g = g;
this.group = group;
assert (this.group.contains(g));
this.commitmentsArrayList = generateCommitments();
}
/**
* commitments[i] = g ^ polynomial.coefficients[i]
* @return commitments
*/
private ArrayList<T> generateCommitments() {
Polynomial polynomial = getPolynomial();
BigInteger[] coefficients = polynomial.getCoefficients();
ArrayList<T> commitments = new ArrayList<T>(t + 1);
for (int i = 0 ; i <= t;i++){
commitments.add(i,group.multiply(g,coefficients[i]));
}
return commitments;
}
/**
* Compute verification value (g^{share value}) using coefficient commitments sent by dealer and my share id.
* @param j my share holder id
* @param commitments commitments to polynomial coefficients of share (received from dealer)
* @param group
*
* @return product of Aik ^ (j ^ k) == g ^ polynomial(i)
*/
public static <T> T computeVerificationValue(int j, ArrayList<T> commitments, Group<T> group) {
T v = group.zero();
BigInteger power = BigInteger.ONE;
BigInteger J = BigInteger.valueOf(j);
for (int k = 0 ; k < commitments.size() ; k ++){
v = group.add(v,group.multiply(commitments.get(k),power));
power = power.multiply(J);
}
return v;
}
/**
* getter
* @return generator of group
*/
public T getGenerator() {
return g;
}
/**
* getter
* @return group
*/
public Group<T> getGroup(){
return group;
}
/**
* getter
* @return commitmentsArrayList
*/
public ArrayList<T> getCommitmentsArrayList() {
return commitmentsArrayList;
}
}

View File

@ -0,0 +1,66 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import java.math.BigInteger;
/**
* Created by Tzlil on 1/28/2016.
*
* container of lagrange polynomial
*
* Constructor is private (use {@link #lagrangePolynomials(Polynomial.Point[], Arithmetic)} to construct)
*
* l = (evaluate/divisor)* polynomial
*
* Note : image and divisor stored separately for avoiding lose of information by division
*/
class LagrangePolynomial{
public final Polynomial polynomial;
public final BigInteger image;
public final BigInteger divisor;
/**
* inner constructor, stores all given parameters
* @param polynomial
* @param image
* @param divisor
*/
private LagrangePolynomial(Polynomial polynomial, BigInteger image, BigInteger divisor) {
this.polynomial = polynomial;
this.image = image;
this.divisor = divisor;
}
/**
* static method
* @param points array points s.t there are no couple of points that shares the same x value
*
* @return the lagrange polynomials that mach to given points.
* in case there exists i != j s.t points[i].x == points[j].x returns null.
*/
public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points,Arithmetic<BigInteger> arithmetic) {
Polynomial one = new Polynomial(new BigInteger[]{BigInteger.ONE},arithmetic);
LagrangePolynomial[] lagrangePolynomials = new LagrangePolynomial[points.length];
Polynomial[] factors = new Polynomial[points.length];
for (int i = 0 ; i < factors.length ; i++){
factors[i] = new Polynomial(new BigInteger[]{points[i].x.negate(),BigInteger.ONE},arithmetic); // X - Xi
}
Polynomial product;
BigInteger divisor;
for(int i = 0; i < points.length; i ++) {
product = one;
divisor = BigInteger.ONE;
for (int j = 0; j < points.length; j++) {
if (i != j) {
divisor = arithmetic.mul(divisor,arithmetic.sub(points[i].x,points[j].x));
product = product.mul(factors[j]);
}
}
if(divisor.equals(BigInteger.ZERO))
return null;
lagrangePolynomials[i] = new LagrangePolynomial(product,points[i].y,divisor);
}
return lagrangePolynomials;
}
}

View File

@ -0,0 +1,208 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Created by Tzlil on 1/27/2016.
*/
public class Polynomial implements Comparable<Polynomial> {
private final int degree;
private final BigInteger[] coefficients;
private final Arithmetic<BigInteger> arithmetic;
/**
* constructor
* @param coefficients
* @param arithmetic
* degree set as max index such that coefficients[degree] not equals zero
*/
public Polynomial(BigInteger[] coefficients,Arithmetic<BigInteger> arithmetic) {
int d = coefficients.length - 1;
while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){
d--;
}
this.degree = d;
this.coefficients = coefficients;
this.arithmetic = arithmetic;
}
/**
* Compare to another polynomial (order by degree, then coefficients).
*/
@Override
public int compareTo(Polynomial other) {
if (this.degree != other.degree)
return this.degree - other.degree;
int compare;
for (int i = degree; i >= degree ; i--){
compare = this.coefficients[i].compareTo(other.coefficients[i]);
if (compare != 0){
return compare;
}
}
return 0;
}
/**
* @param x
* @return sum of coefficients[i] * (x ^ i)
*/
public BigInteger evaluate(BigInteger x){
BigInteger result = BigInteger.ZERO;
BigInteger power = BigInteger.ONE;
for(int i = 0 ; i <= degree ; i++){
result = arithmetic.add(result,arithmetic.mul(coefficients[i],power));
power = power.multiply(x);
}
return result;
}
/**
* @param points
* @return polynomial of minimal degree which goes through all points.
* If there exists i != j s.t points[i].x == points[j].x, method returns null.
*/
public static Polynomial interpolation(Point[] points, Arithmetic<BigInteger> arithmetic) {
LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points,arithmetic);
if (l == null){
return null;
}
// product = product of l[i].divisor
BigInteger product = BigInteger.ONE;
for (int i = 0; i < l.length;i++){
product = arithmetic.mul(product,l[i].divisor);
}
// factor[i] = product divided by l[i].divisor = product of l[j].divisor s.t j!=i
BigInteger[] factors = new BigInteger[l.length];
for (int i = 0; i < l.length;i++){
factors[i] = arithmetic.div(product,l[i].divisor);
}
int degree = l[0].polynomial.degree;
// coefficients[j] = (sum of l[i].evaluate * factor[i] * l[i].coefficients[j] s.t i!=j) divide by product =
// = sum of l[i].evaluate * l[i].coefficients[j] / l[i].divisor s.t i!=j
BigInteger[] coefficients = new BigInteger[degree + 1];
for (int j = 0; j < coefficients.length;j++){
coefficients[j] = BigInteger.ZERO;
for (int i = 0; i < l.length; i++){
BigInteger current = arithmetic.mul(l[i].image,factors[i]);
current = arithmetic.mul(current,l[i].polynomial.coefficients[j]);
coefficients[j] = arithmetic.add(coefficients[j],current);
}
coefficients[j] = arithmetic.div(coefficients[j],product);
}
return new Polynomial(coefficients,arithmetic);
}
/**
* @param other
* @return new Polynomial of degree max(this degree,other degree) s.t for all x
* new.evaluate(x) = this.evaluate(x) + other.evaluate(x)
*/
public Polynomial add(Polynomial other){
Polynomial bigger,smaller;
if(this.degree < other.degree){
bigger = other;
smaller = this;
}else{
bigger = this;
smaller = other;
}
BigInteger[] coefficients = bigger.getCoefficients();
for (int i = 0; i <= smaller.degree ; i++){
coefficients[i] = arithmetic.add(smaller.coefficients[i],bigger.coefficients[i]);
}
return new Polynomial(coefficients,other.arithmetic);
}
/**
* @param constant
* @return new Polynomial of degree this.degree s.t for all x
* new.evaluate(x) = constant * this.evaluate(x)
*/
public Polynomial mul(BigInteger constant){
BigInteger[] coefficients = this.getCoefficients();
for (int i = 0; i <= this.degree ; i++){
coefficients[i] = arithmetic.mul(constant,coefficients[i]);
}
return new Polynomial(coefficients,arithmetic);
}
/**
* @param other
* @return new Polynomial of degree this degree + other degree + 1 s.t for all x
* new.evaluate(x) = this.evaluate(x) * other.evaluate(x)
*/
public Polynomial mul(Polynomial other){
BigInteger[] coefficients = new BigInteger[this.degree + other.degree + 1];
Arrays.fill(coefficients,BigInteger.ZERO);
for (int i = 0; i <= this.degree ; i++){
for (int j = 0; j <= other.degree; j++){
coefficients[i+j] = arithmetic.add(coefficients[i+j],arithmetic.mul(this.coefficients[i],other.coefficients[j]));
}
}
return new Polynomial(coefficients,arithmetic);
}
/** getter
* @return copy of coefficients
*/
public BigInteger[] getCoefficients() {
return Arrays.copyOf(coefficients,coefficients.length);
}
/** getter
* @return degree
*/
public int getDegree() {
return degree;
}
/**
* inner class
* container for (x,y) x from range and y from evaluate of polynomial
*/
public static class Point implements java.io.Serializable {
public final BigInteger x;
public final BigInteger y;
/**
* constructor
* @param x
* @param polynomial y = polynomial.evaluate(x)
*/
public Point(BigInteger x, Polynomial polynomial) {
this.x = x;
this.y = polynomial.evaluate(x);
}
/**
* constructor
* @param x
* @param y
*/
public Point(BigInteger x,BigInteger y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if(!super.equals(obj))
return false;
Point other = (Point)obj;
return this.x.equals(other.x) && this.y.equals(other.y);
}
}
}

View File

@ -0,0 +1,123 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
* an implementation of Shamire's secret sharing scheme
*/
public class SecretSharing{
/**
* threshold
*/
protected final int t;
/**
* number of shares
*/
protected final int n;
/**
* a large prime
*/
protected final BigInteger q;
/**
* random polynomial of degree s.t polynomial.evaluate(0) = secret
*/
protected final Polynomial polynomial;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
*/
public SecretSharing(int t, int n, BigInteger zi, Random random, BigInteger q) {
this.q = q;
this.t = t;
this.n = n;
this.polynomial = generateRandomPolynomial(zi,random);
}
/**
* @param x
* @param random
* @return new Polynomial polynomial of degree t ,such that
* 1. polynomial(0) = x
* 2. polynomial coefficients randomly chosen from Zq (except of coefficients[0] = x)
*/
private Polynomial generateRandomPolynomial(BigInteger x, Random random) {
BigInteger[] coefficients = new BigInteger[t + 1];
coefficients[0] = x.mod(q);
int bits = q.bitLength();
for (int i = 1 ; i <= t; i++ ){
coefficients[i] = new BigInteger(bits,random).mod(q);
}
return new Polynomial(coefficients,new Fp(q));
}
/**
* @param i in range of [1,...n]
*
* @return polynomial.evaluate(i)
*/
public Polynomial.Point getShare(int i){
assert (i > 0 && i <= n);
return new Polynomial.Point(BigInteger.valueOf(i), polynomial);
}
/**
* @param shares - subset of the original shares
*
* @return evaluate of interpolation(shares) at x = 0
*/
public static BigInteger recoverSecret(Polynomial.Point[] shares, Arithmetic<BigInteger> arithmetic) {
return recoverPolynomial(shares,arithmetic).evaluate(BigInteger.ZERO);
}
/**
* @param shares - subset of the original shares
*
* @return interpolation(shares)
*/
public static Polynomial recoverPolynomial(Polynomial.Point[] shares, Arithmetic<BigInteger> arithmetic) {
return Polynomial.interpolation(shares,arithmetic);
}
/**
* getter
* @return threshold
*/
public int getT() {
return t;
}
/**
* getter
* @return number of share holders
*/
public int getN() {
return n;
}
/**
* getter
* @return the prime was given in the constructor
*/
public BigInteger getQ() {
return q;
}
/**
* getter
* @return the polynomial was generated in constructor
*/
public Polynomial getPolynomial() {
return polynomial;
}
}

View File

@ -0,0 +1,38 @@
package meerkat.crypto.utils;
/**
* Created by Tzlil on 3/17/2016.
* defines the properties of the traditional operations : add,sub,mul,div
* between two objects of type T
*/
public interface Arithmetic<T> {
/**
* addition
* @param a
* @param b
* @return a + b
*/
T add(T a, T b);
/**
* subtraction
* @param a
* @param b
* @return a - b
*/
T sub(T a, T b);
/**
* multiplication
* @param a
* @param b
* @return a * b
*/
T mul(T a, T b);
/**
* division
* @param a
* @param b
* @return a / b
*/
T div(T a, T b);
}

View File

@ -0,0 +1,44 @@
package meerkat.crypto.utils.concrete;
import meerkat.crypto.utils.Arithmetic;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import java.math.BigInteger;
/**
* Created by Tzlil on 3/17/2016.
* an implementation of Arithmetic<BigInteger> over prime fields: integers modulo p
*/
public class Fp implements Arithmetic<BigInteger> {
public final BigInteger p;
private final Zpstar zp;
/**
* constructor
* @param p prime
*/
public Fp(BigInteger p) {
this.p = p;
this.zp = new Zpstar(p);
}
@Override
public BigInteger add(BigInteger a, BigInteger b){
return a.add(b).mod(p);
}
@Override
public BigInteger sub(BigInteger a, BigInteger b){
return a.add(p).subtract(b).mod(p);
}
@Override
public BigInteger mul(BigInteger a, BigInteger b){
return zp.add(a,b);
}
@Override
public BigInteger div(BigInteger a, BigInteger b){
return mul(a,zp.negate(b));
}
}

View File

@ -0,0 +1,46 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message Payload {
enum Type {
SHARE = 0;
COMMITMENT = 1;
COMPLAINT = 2;
DONE = 3;
ANSWER = 4;
YCOMMITMENT = 5;
YCOMPLAINT = 6;
YANSWER = 7;
ABORT = 8;
}
// Type of message in protocol
Type type = 1;
oneof payload_data {
IDMessage id = 5;
ShareMessage share = 6;
CommitmentMessage commitment = 7;
}
}
message IDMessage {
int32 id = 1;
}
message ShareMessage {
int32 i = 1;
int32 j = 2;
bytes share = 3;
// For double shares (used in GJKR protocol)
bytes share_t = 4;
}
message CommitmentMessage {
int32 k = 1;
bytes commitment = 2;
}

View File

@ -0,0 +1,73 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import java.math.BigInteger;
import java.util.*;
/**
* Created by Tzlil on 3/21/2016.
*/
public class DKGMaliciousUser<T> extends User<T> {
private final Protocol<T> maliciousDkg;
private final Set<Integer> falls;
public DKGMaliciousUser(Protocol<T> dkg, Protocol<T> maliciousDKG, Channel channel, Set<Integer> falls) {
super(dkg, channel);
this.falls = falls;
this.maliciousDkg = maliciousDKG;
maliciousDKG.setParties(parties);
}
public static Set<Integer> selectFallsRandomly(Set<Integer> ids, Random random){
Set<Integer> falls = new HashSet<Integer>();
ArrayList<Integer> idsList = new ArrayList<Integer>();
for (int id : ids){
idsList.add(id);
}
int fallsSize = random.nextInt(idsList.size()) + 1;// 1 - (n-1)
while (falls.size() < fallsSize){
falls.add(idsList.remove(random.nextInt(idsList.size())));
}
return falls;
}
public static <T> Protocol<T> generateMaliciousDKG(Protocol<T> dkg,Channel channel,Random random){
BigInteger q = dkg.getQ();
BigInteger zi = new BigInteger(q.bitLength(), random).mod(q);
Protocol<T> malicious = new Protocol<T>(dkg.getT(),dkg.getN(),zi,random,dkg.getQ()
,dkg.getGenerator(),dkg.getGroup(),dkg.getId(),dkg.getEncoder());
malicious.setChannel(channel);
return malicious;
}
@Override
public void stage1() {
dkg.broadcastCommitments();
sendSecrets(); //insteadof crypto.sendSecrets(channel);
}
@Override
public void stage3() {
maliciousDkg.answerAllComplainingPlayers();
}
@Override
public void stage4(){
// do nothing
}
private void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
if(falls.contains(j)){
maliciousDkg.sendSecret(j);
}else {
dkg.sendSecret(j);
}
}
}
}
}

View File

@ -0,0 +1,170 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.ChannelImpl;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.crypto.utils.BigIntegerByteEncoder;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import org.factcenter.qilin.util.ByteEncoder;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/21/2016.
*/
public class DKGTest {
int tests = 10;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
Group<BigInteger> group = new Zpstar(p);
Arithmetic<BigInteger> arithmetic = new Fp(q);
int t = 9;
int n = 20;
public void oneTest(Testable testable) throws Exception {
for (int i = 0; i < testable.threads.length ; i++){
testable.threads[i].start();
}
for (int i = 0; i < testable.threads.length ; i++){
testable.threads[i].join();
}
// got the right public value
BigInteger publicValue = group.multiply(testable.g,testable.secret);
for (int i: testable.valids){
assert (testable.dkgs[i - 1].getPublicValue().equals(publicValue));
}
// assert valid verification values
BigInteger expected,verification;
for (int i: testable.valids){
expected = group.multiply(testable.g, testable.dkgs[i - 1].getShare().y);
verification = VerifiableSecretSharing.computeVerificationValue(i, testable.dkgs[i - 1].getCommitments(), group);
assert (expected.equals(verification));
}
// restore the secret from shares
ArrayList<Polynomial.Point> sharesList = new ArrayList<Polynomial.Point>();
for (int i: testable.valids){
sharesList.add(testable.dkgs[i - 1].getShare());
}
Polynomial.Point[] shares = new Polynomial.Point[sharesList.size()];
for (int i = 0; i < shares.length; i ++){
shares[i] = sharesList.get(i);
}
BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic);
assert (calculatedSecret.equals(testable.secret));
}
@Test
public void test() throws Exception {
Testable testable;
for (int i = 0; i < tests; i++){
testable = new Testable(new Random());
oneTest(testable);
}
}
class Testable{
Set<Integer> valids;
Set<Integer> QUAL;
Set<Integer> aborted;
Set<Integer> malicious;
User<BigInteger>[] dkgs;
Thread[] threads;
BigInteger g;
BigInteger secret;
public Testable(Random random) {
this.dkgs = new User[n];
this.valids = new HashSet<Integer>();
this.QUAL = new HashSet<Integer>();
this.aborted = new HashSet<Integer>();
this.malicious = new HashSet<Integer>();
this.threads = new Thread[n];
this.g = sampleGenerator(random);
ArrayList<Integer> ids = new ArrayList<Integer>();
for (int id = 1; id<= n ; id++){
ids.add(id);
}
int id;
BigInteger s;
Protocol<BigInteger> dkg;
this.secret = BigInteger.ZERO;
ChannelImpl channels = new ChannelImpl();
ByteEncoder<BigInteger> byteEncoder = new BigIntegerByteEncoder();
while (!ids.isEmpty()) {
id = ids.remove(random.nextInt(ids.size()));
Channel channel = channels.getChannel(id);
s = randomIntModQ(random);
dkg = new meerkat.crypto.dkg.feldman.Protocol<BigInteger>(t, n, s, random, q, g, group, id,byteEncoder);
dkgs[id - 1] = randomDKGUser(id,channel,dkg,random);
threads[id - 1] = new Thread(dkgs[id - 1]);
if(QUAL.contains(id)){
this.secret = this.secret.add(s).mod(q);
}
}
}
public User<BigInteger> randomDKGUser(int id, Channel channel, Protocol<BigInteger> dkg, Random random){
if (QUAL.size() <= t) {
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(dkg,channel);
}else{
int type = random.nextInt(3);
switch (type){
case 0:// regular
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(dkg,channel);
case 1:// abort
int abortStage = random.nextInt(2) + 1; // 1 or 2
aborted.add(id);
if (abortStage == 2){
QUAL.add(id);
}
return new DKGUserImplAbort(dkg,channel,abortStage);
case 2:// malicious
malicious.add(id);
Set<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> maliciousDKG = DKGMaliciousUser.generateMaliciousDKG(dkg,channel,random);
return new DKGMaliciousUser(dkg,maliciousDKG,channel,falls);
default:
return null;
}
}
}
public BigInteger sampleGenerator(Random random){
BigInteger ZERO = group.zero();
BigInteger g;
do {
g = group.sample(random);
} while (!g.equals(ZERO) && !group.multiply(g, q).equals(ZERO));
return g;
}
public BigInteger randomIntModQ(Random random){
return new BigInteger(q.bitLength(), random).mod(q);
}
}
}

View File

@ -0,0 +1,65 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import meerkat.protobuf.DKG;
import static meerkat.crypto.dkg.comm.MessageUtils.createMessage;
/**
* Created by Tzlil on 3/14/2016.
*/
public class DKGUserImplAbort<T> extends User<T> {
final int abortStage;
int stage;
public DKGUserImplAbort(Protocol<T> dkg, Channel channel, int abortStage) {
super(dkg, channel);
this.abortStage = abortStage;// 1 - 2
this.stage = 1;
}
private void sendAbort(){
channel.broadcastMessage(createMessage(DKG.Payload.Type.ABORT));
}
@Override
protected void stage1() {
if(stage < abortStage)
super.stage1();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage2() {
if(stage < abortStage)
super.stage2();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage3() {
if(stage < abortStage)
super.stage3();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage4() {
if(stage < abortStage)
super.stage4();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
}

View File

@ -0,0 +1,61 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.comm.Channel;
import java.math.BigInteger;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/29/2016.
*/
public class SDKGMaliciousUserImpl<T> extends User<T> {
private final Protocol<T> maliciousSDKG;
private final Set<Integer> falls;
public SDKGMaliciousUserImpl(Protocol<T> sdkg, Protocol<T> maliciousSDKG
, Channel channel, Set<Integer> falls) {
super(sdkg, channel);
this.falls = falls;
this.maliciousSDKG = maliciousSDKG;
maliciousSDKG.setParties(parties);
}
public static<T> Protocol<T> generateMaliciousSDKG(Protocol<T> sdkg,Channel channel,Random random){
BigInteger q = sdkg.getQ();
BigInteger zi = new BigInteger(q.bitLength(), random).mod(q);
Protocol<T> malicious = new Protocol<T>(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ()
,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId(),sdkg.getEncoder());
malicious.setChannel(channel);
return malicious;
}
@Override
public void stage1() {
sdkg.computeAndBroadcastVerificationValues();
sendSecrets(); //insteadof crypto.sendSecrets(channel);
}
@Override
public void stage3() {
maliciousSDKG.answerAllComplainingPlayers();
}
@Override
public void stage4(){
//do nothing
}
private void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
if(falls.contains(j)){
maliciousSDKG.sendSecret(j);
}else {
sdkg.sendSecret(j);
}
}
}
}
}

View File

@ -0,0 +1,206 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.comm.ChannelImpl;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.dkg.feldman.DKGMaliciousUser;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.crypto.utils.BigIntegerByteEncoder;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import org.factcenter.qilin.util.ByteEncoder;
import org.junit.Assert;
import org.junit.Test;
import org.junit.internal.runners.statements.Fail;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Created by Tzlil on 3/29/2016.
* TODO: Separate into multiple tests,
* TODO: Make tests deterministic (using constant seed for random generator)
*/
public class SDKGTest {
private ExecutorService executorService = Executors.newCachedThreadPool();
final static int NUM_TESTS = 10;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
Group<BigInteger> group = new Zpstar(p);
Arithmetic<BigInteger> arithmetic = new Fp(q);
int t = 1;
int n = 20;
Random rand = new Random(1);
public void oneTest(Testable testable) throws Exception {
for (int i = 0; i < testable.sdkgs.length ; i++){
testable.futures[i] = executorService.submit(testable.sdkgs[i]);
}
for (int i = 0; i < testable.futures.length ; i++){
testable.futures[i].get();
}
// got the right public value
BigInteger publicValue = group.multiply(testable.g,testable.secret);
for (int i: testable.valids){
assert (testable.sdkgs[i - 1].getPublicValue().equals(publicValue));
}
// assert valid verification values
BigInteger expected,verification;
for (int i: testable.valids){
expected = group.multiply(testable.g, testable.sdkgs[i - 1].getShare().y);
verification = VerifiableSecretSharing.computeVerificationValue(i, testable.sdkgs[i - 1].getCommitments(), group);
assert (expected.equals(verification));
}
// restore the secret from shares
ArrayList<Polynomial.Point> sharesList = new ArrayList<Polynomial.Point>();
for (int i: testable.valids){
sharesList.add(testable.sdkgs[i - 1].getShare());
}
Polynomial.Point[] shares = new Polynomial.Point[sharesList.size()];
for (int i = 0; i < shares.length; i ++){
shares[i] = sharesList.get(i);
}
BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic);
assert (calculatedSecret.equals(testable.secret));
}
@Test
public void test() throws Exception {
Testable testable;
for (int i = 0; i < NUM_TESTS; i++) {
testable = new Testable(n, t, group, q, rand);
oneTest(testable);
}
}
static class Testable {
Set<Integer> valids;
Set<Integer> QUAL;
Set<Integer> aborted;
Set<Integer> malicious;
User<BigInteger>[] sdkgs;
Future<?>[] futures;
BigInteger g;
BigInteger h;
BigInteger secret;
Group<BigInteger> group;
int n;
int t;
BigInteger q;
Random random;
ChannelImpl channels = new ChannelImpl();
public Testable(int n, int t, Group<BigInteger> group, BigInteger q, Random random) {
this.n = n;
this.t = t;
this.group = group;
this.q = q;
this.random = random;
this.sdkgs = new User[n];
this.valids = new HashSet<Integer>();
this.QUAL = new HashSet<Integer>();
this.aborted = new HashSet<Integer>();
this.malicious = new HashSet<Integer>();
this.futures = new Future[n];
this.g = sampleGenerator(random);
this.h = group.multiply(g,randomIntModQ(random));
ArrayList<Integer> ids = new ArrayList<Integer>();
for (int id = 1; id<= n ; id++){
ids.add(id);
}
int id;
BigInteger s;
Channel channel;
Protocol<BigInteger> sdkg;
this.secret = BigInteger.ZERO;
ByteEncoder<BigInteger> encoder = new BigIntegerByteEncoder();
while (!ids.isEmpty()) {
id = ids.remove(random.nextInt(ids.size()));
s = randomIntModQ(random);
channel = channels.getChannel(id);
sdkg = new Protocol<BigInteger>(t, n, s, random, q, g , h, group, id,encoder);
sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg);
if(QUAL.contains(id)){
this.secret = this.secret.add(s).mod(q);
}
}
}
enum UserType {
HONEST,
FAILSTOP,
MALICIOUS,
}
public User<BigInteger> newSDKGUser(int id, Channel channel, Protocol<BigInteger> sdkg, UserType userType) {
switch(userType) {
case HONEST:
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(sdkg,channel);
case FAILSTOP:
int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3
aborted.add(id);
if (abortStage > 1){
QUAL.add(id);
}
return new SDKGUserImplAbort(sdkg,channel,abortStage);
case MALICIOUS:
malicious.add(id);
Set<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random);
return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls);
}
fail("Unknown user type");
return null;
}
public User<BigInteger> randomSDKGUser(int id, Channel channel, Protocol<BigInteger> sdkg){
if (QUAL.size() <= t) {
return newSDKGUser(id, channel, sdkg, UserType.HONEST);
} else {
UserType type = UserType.values()[random.nextInt(UserType.values().length)];
return newSDKGUser(id, channel, sdkg, type);
}
}
public BigInteger sampleGenerator(Random random){
BigInteger ZERO = group.zero();
BigInteger g;
do {
g = group.sample(random);
} while (!g.equals(ZERO) && !group.multiply(g, q).equals(ZERO));
return g;
}
public BigInteger randomIntModQ(Random random){
return new BigInteger(q.bitLength(), random).mod(q);
}
}
}

View File

@ -0,0 +1,80 @@
package meerkat.crypto.dkg.gjkr;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.dkg.comm.MessageUtils;
import meerkat.comm.Channel;
import meerkat.protobuf.Comm;
import meerkat.protobuf.DKG;
/**
* Created by Tzlil on 3/14/2016.
*/
public class SDKGUserImplAbort<T> extends User<T> {
public static class AbortException extends RuntimeException {
}
final int abortStage;
int stage;
public SDKGUserImplAbort(Protocol<T> sdkg, Channel channel, int abortStage) {
super(sdkg, channel);
this.abortStage = abortStage;// 1 - 4
this.stage = 1;
}
private void abort(){
//stopReceiver();
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT));
throw new AbortException();
}
@Override
protected void stage1() {
if(stage < abortStage)
super.stage1();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage2() {
if(stage < abortStage)
super.stage2();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage3() {
if(stage < abortStage)
super.stage3();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage4() {
if(stage < abortStage)
super.stage4();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
public void run() {
try {
super.run();
} catch (AbortException e) {
// Expected
}
}
}

View File

@ -0,0 +1,68 @@
package meerkat.crypto.secretsharing.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;
/**
* Created by Tzlil on 1/29/2016.
*/
public class VerifiableSecretSharingTest {
VerifiableSecretSharing[] verifiableSecretSharingArray;
int tests = 1 << 10;
Random random;
@Before
public void settings(){
BigInteger p = BigInteger.valueOf(2903);
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
Zpstar zpstar = new Zpstar(p);
random = new Random();
BigInteger g;
BigInteger ZERO = zpstar.zero();
do{
g = zpstar.sample(random);
}while (!g.equals(ZERO) && !zpstar.multiply(g,q).equals(ZERO));// sample from QRZp*
int t = 8;
int n = 20;
verifiableSecretSharingArray = new VerifiableSecretSharing[tests];
for (int i = 0; i < verifiableSecretSharingArray.length; i++){
verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n
,new BigInteger(q.bitLength(),random).mod(q),random,q,g,zpstar);
}
}
public void oneTest(VerifiableSecretSharing<BigInteger> verifiableSecretSharing) throws Exception {
int n = verifiableSecretSharing.getN();
Group<BigInteger> zpstar = verifiableSecretSharing.getGroup();
BigInteger g = verifiableSecretSharing.getGenerator();
Polynomial.Point[] shares = new Polynomial.Point[n];
ArrayList<BigInteger> commitments = verifiableSecretSharing.getCommitmentsArrayList();
BigInteger[] verifications = new BigInteger[n];
for (int i = 1 ; i <= shares.length; i ++){
shares[i - 1] = verifiableSecretSharing.getShare(i);
verifications[i - 1] = VerifiableSecretSharing.computeVerificationValue(i,commitments,zpstar);
}
BigInteger expected;
for (int i = 0 ; i < shares.length ; i++){
expected = zpstar.multiply(g,shares[i].y);
assert (expected.equals(verifications[i]));
}
}
@Test
public void secretSharingTest() throws Exception {
for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){
oneTest(verifiableSecretSharingArray[i]);
}
}
}

View File

@ -0,0 +1,46 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class AddTest {
Polynomial[] arr1;
Polynomial[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new Polynomial[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
}
}
public void oneTest(Polynomial p1, Polynomial p2){
Polynomial sum = p1.add(p2);
BigInteger x = new BigInteger(bits,random);
assert(sum.evaluate(x).equals(p1.evaluate(x).add(p2.evaluate(x))));
}
@Test
public void addTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,68 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 1/27/2016.
*/
public class InterpolationTest {
Polynomial[] polynomials;
int tests = 1 << 10;
int maxDegree = 15;
int bits = 128;
Random random;
Polynomial.Point[][] pointsArrays;
Arithmetic<BigInteger> arithmetic;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
@Before
public void settings(){
random = new Random();
polynomials = new Polynomial[tests];
pointsArrays = new Polynomial.Point[tests][];
arithmetic = new Fp(p);
for (int i = 0; i < polynomials.length; i++){
polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p);
pointsArrays[i] = randomPoints(polynomials[i]);
}
}
public Polynomial.Point[] randomPoints(Polynomial polynomial){
Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1];
BigInteger x;
Set<BigInteger> set = new HashSet();
for (int i = 0; i < points.length; i++){
x = new BigInteger(bits,random).mod(p);
if(set.contains(x)){
i--;
continue;
}
set.add(x);
points[i] = new Polynomial.Point(x,polynomial);
}
return points;
}
public void oneTest(Polynomial p, Polynomial.Point[] points) throws Exception {
Polynomial interpolation = Polynomial.interpolation(points,arithmetic);
assert (p.compareTo(interpolation) == 0);
}
@Test
public void interpolationTest() throws Exception {
for (int i = 0; i < polynomials.length; i ++){
oneTest(polynomials[i],pointsArrays[i]);
}
}
}

View File

@ -0,0 +1,48 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class MulByConstTest {
Polynomial[] arr1;
BigInteger[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new BigInteger[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = new BigInteger(bits,random);
}
}
public void oneTest(Polynomial p, BigInteger c){
Polynomial product = p.mul(c);
BigInteger x = new BigInteger(bits,random);
assert(product.evaluate(x).equals(p.evaluate(x).multiply(c)));
}
@Test
public void mulByConstTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,48 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class MulTest {
Polynomial[] arr1;
Polynomial[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new Polynomial[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
}
}
public void oneTest(Polynomial p1, Polynomial p2){
Polynomial product = p1.mul(p2);
BigInteger x = new BigInteger(bits,random);
assert(product.evaluate(x).equals(p1.evaluate(x).multiply(p2.evaluate(x))));
}
@Test
public void mulTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,64 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.factcenter.qilin.primitives.CyclicGroup;
import org.factcenter.qilin.primitives.concrete.Zn;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by Tzlil on 1/29/2016.
*/
public class SecretSharingTest {
SecretSharing[] secretSharingArray;
BigInteger[] secrets;
CyclicGroup<BigInteger> group;
int tests = 1 << 10;
Random random;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
@Before
public void settings(){
group = new Zn(q);
int t = 9;
int n = 20;
random = new Random();
secretSharingArray = new SecretSharing[tests];
secrets = new BigInteger[tests];
for (int i = 0; i < secretSharingArray.length; i++){
secrets[i] = group.sample(random);
secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,q);
}
}
public void oneTest(SecretSharing secretSharing, BigInteger secret) throws Exception {
int t = secretSharing.getT();
int n = secretSharing.getN();
Polynomial.Point[] shares = new Polynomial.Point[t + 1];
List<Integer> indexes = new ArrayList<Integer>(n);
for (int i = 1 ; i <= n; i ++){
indexes.add(i);
}
for (int i = 0 ; i < shares.length ; i++){
shares[i] = secretSharing.getShare(indexes.remove(random.nextInt(indexes.size())));
}
BigInteger calculated = SecretSharing.recoverSecret(shares,new Fp(q));
assert (secret.equals(calculated));
}
@Test
public void secretSharingTest() throws Exception {
for (int i = 0 ; i < secretSharingArray.length; i ++){
oneTest(secretSharingArray[i],secrets[i]);
}
}
}

View File

@ -0,0 +1,28 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
/**
* Created by Tzlil on 4/7/2016.
*/
public class BigIntegerByteEncoder implements org.factcenter.qilin.util.ByteEncoder<BigInteger> {
@Override
public byte[] encode(BigInteger input) {
return input.toByteArray();
}
@Override
public BigInteger decode(byte[] input) {
return new BigInteger(1,input);
}
@Override
public int getMinLength() {
return 0;
}
@Override
public BigInteger denseDecode(byte[] input) {
return decode(input);
}
}

View File

@ -0,0 +1,30 @@
package meerkat.crypto.utils;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.utils.concrete.Fp;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class GenerateRandomPolynomial {
public static Polynomial generateRandomPolynomial(int degree, int bits, Random random, Arithmetic<BigInteger> arithmetic) {
BigInteger[] coefficients = new BigInteger[degree + 1];
for (int i = 0 ; i <= degree; i++ ){
coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... q-1]
}
return new Polynomial(coefficients,arithmetic);
}
public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) {
BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random,new Fp(p)).getCoefficients();
for (int i = 0; i<coefficients.length;i++){
coefficients[i] = coefficients[i].mod(p);
}
return new Polynomial(coefficients,new Fp(p));
}
}

View File

@ -0,0 +1,30 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 3/28/2016.
*/
public class GenerateRandomPrime {
private final static int Certainty = 10000;
public final static BigInteger SafePrime100Bits = new BigInteger("146407324427772525685319783363");
public static BigInteger generateRandomPrime(int bits, Random random) {
BigInteger p;
do {
p = new BigInteger(bits, random);
} while (!p.isProbablePrime(Certainty));
return p;
}
public static BigInteger generateRandomSafePrime(int bits, Random random) {
BigInteger p;
BigInteger q;
do {
p = generateRandomPrime(bits, random);
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
} while (!q.isProbablePrime(Certainty));
return q;
}
}

View File

@ -0,0 +1,28 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
/**
* Created by Tzlil on 4/8/2016.
*/
public class Z implements Arithmetic<BigInteger> {
@Override
public BigInteger add(BigInteger a, BigInteger b) {
return a.add(b);
}
@Override
public BigInteger sub(BigInteger a, BigInteger b) {
return a.subtract(b);
}
@Override
public BigInteger mul(BigInteger a, BigInteger b) {
return a.multiply(b);
}
@Override
public BigInteger div(BigInteger a, BigInteger b) {
return a.divide(b);
}
}

Binary file not shown.

View File

@ -1,7 +1,6 @@
#Tue Aug 05 03:26:05 IDT 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip
distributionSha256Sum=4647967f8de78d6d6d8093cdac50f368f8c2b8038f41a5afe1c3bce4c69219a9
#Fri Jan 29 21:00:29 IST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip

10
gradlew vendored
View File

@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

View File

@ -1 +1 @@
/bin/
/bin/

View File

@ -1,219 +1,219 @@
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
}
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'application'
apply plugin: 'maven-publish'
mainClassName='Demo'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "Meerkat Voting Common Library"
// Your project version
version = "0.0"
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'
// Google protobufs
compile 'com.google.protobuf:protobuf-java:3.+'
// ListeningExecutor
compile 'com.google.guava:guava:15.0'
// Crypto
compile 'org.factcenter.qilin:qilin:1.2+'
compile 'org.bouncycastle:bcprov-jdk15on:1.53'
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
}
/*==== You probably don't have to edit below this line =======*/
// Setup test configuration that can appear as a dependency in
// other subprojects
configurations {
testOutput.extendsFrom (testCompile)
}
task testJar(type: Jar, dependsOn: testClasses) {
classifier = 'tests'
from sourceSets.test.output
}
artifacts {
testOutput testJar
}
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from
// the command line to the JavaExec task.
systemProperties System.properties
}
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
task mavenCapsule(type: MavenCapsule){
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule){
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
/*===================================
* Repositories
*===================================*/
repositories {
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 ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
}
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'application'
apply plugin: 'maven-publish'
mainClassName='Demo'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "Meerkat Voting Common Library"
// Your project version
version = "0.0"
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'
// Google protobufs
compile 'com.google.protobuf:protobuf-java:3.+'
// ListeningExecutor
compile 'com.google.guava:guava:15.0'
// Crypto
compile 'org.factcenter.qilin:qilin:1.2+'
compile 'org.bouncycastle:bcprov-jdk15on:1.53'
testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+'
}
/*==== You probably don't have to edit below this line =======*/
// Setup test configuration that can appear as a dependency in
// other subprojects
configurations {
testOutput.extendsFrom (testCompile)
}
task testJar(type: Jar, dependsOn: testClasses) {
classifier = 'tests'
from sourceSets.test.output
}
artifacts {
testOutput testJar
}
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from
// the command line to the JavaExec task.
systemProperties System.properties
}
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
task mavenCapsule(type: MavenCapsule){
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule){
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
/*===================================
* Repositories
*===================================*/
repositories {
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 ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}

View File

@ -1,29 +1,29 @@
import com.google.protobuf.ByteString;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.io.IOException;
/**
* Created by talm on 10/26/15.
*/
public class Demo {
public static void main(String args[]) {
System.out.println("Nothing to see yet");
BulletinBoardMessage msg;
UnsignedBulletinBoardMessage msgContents = UnsignedBulletinBoardMessage.newBuilder()
.addTag("test")
.setData(ByteString.copyFromUtf8("some data"))
.build();
msg = BulletinBoardMessage.newBuilder()
.setMsg(msgContents)
.build();
try {
msg.writeTo(System.err);
} catch (IOException e) {
// Ignore
}
}
}
import com.google.protobuf.ByteString;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.io.IOException;
/**
* Created by talm on 10/26/15.
*/
public class Demo {
public static void main(String args[]) {
System.out.println("Nothing to see yet");
BulletinBoardMessage msg;
UnsignedBulletinBoardMessage msgContents = UnsignedBulletinBoardMessage.newBuilder()
.addTag("test")
.setData(ByteString.copyFromUtf8("some data"))
.build();
msg = BulletinBoardMessage.newBuilder()
.setMsg(msgContents)
.build();
try {
msg.writeTo(System.err);
} catch (IOException e) {
// Ignore
}
}
}

View File

@ -1,63 +1,63 @@
package meerkat.bulletinboard;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.*;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Collection;
import java.util.List;
/**
* Created by talm on 24/10/15.
*/
public interface BulletinBoardClient {
/**
* Initialize the client to use some specified servers
* @param clientParams contains the parameters required for the client setup
*/
void init(BulletinBoardClientParams clientParams);
/**
* Post a message to the bulletin board in a synchronous manner
* @param msg is the message to be posted
* @return a unique message ID for the message, that can be later used to retrieve the batch
* @throws CommunicationException
*/
MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException;
/**
* Check how "safe" a given message is in a synchronous manner
* @param id is the unique message identifier for retrieval
* @return a normalized "redundancy score" from 0 (local only) to 1 (fully published)
*/
float getRedundancy(MessageID id);
/**
* Read all messages posted matching the given filter in a synchronous manner
* Note that if messages haven't been "fully posted", this might return a different
* set of messages in different calls. However, messages that are fully posted
* are guaranteed to be included.
* @param filterList return only messages that match the filters (null means no filtering)
* @return the list of messages
*/
List<BulletinBoardMessage> readMessages(MessageFilterList filterList);
/**
* Create a SyncQuery to test against that corresponds with the current server state for a specific filter list
* Should only be called on instances for which the actual server contacted is known (i.e. there is only one server)
* @param GenerateSyncQueryParams defines the required information needed to generate the query
* These are represented as fractions of the total number of relevant messages
* @return The generated SyncQuery
* @throws CommunicationException when no DB can be contacted
*/
SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException;
/**
* Closes all connections, if any.
* This is done in a synchronous (blocking) way.
*/
void close();
}
package meerkat.bulletinboard;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.Voting.*;
import static meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Collection;
import java.util.List;
/**
* Created by talm on 24/10/15.
*/
public interface BulletinBoardClient {
/**
* Initialize the client to use some specified servers
* @param clientParams contains the parameters required for the client setup
*/
void init(BulletinBoardClientParams clientParams);
/**
* Post a message to the bulletin board in a synchronous manner
* @param msg is the message to be posted
* @return a unique message ID for the message, that can be later used to retrieve the batch
* @throws CommunicationException
*/
MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException;
/**
* Check how "safe" a given message is in a synchronous manner
* @param id is the unique message identifier for retrieval
* @return a normalized "redundancy score" from 0 (local only) to 1 (fully published)
*/
float getRedundancy(MessageID id);
/**
* Read all messages posted matching the given filter in a synchronous manner
* Note that if messages haven't been "fully posted", this might return a different
* set of messages in different calls. However, messages that are fully posted
* are guaranteed to be included.
* @param filterList return only messages that match the filters (null means no filtering)
* @return the list of messages
*/
List<BulletinBoardMessage> readMessages(MessageFilterList filterList);
/**
* Create a SyncQuery to test against that corresponds with the current server state for a specific filter list
* Should only be called on instances for which the actual server contacted is known (i.e. there is only one server)
* @param GenerateSyncQueryParams defines the required information needed to generate the query
* These are represented as fractions of the total number of relevant messages
* @return The generated SyncQuery
* @throws CommunicationException when no DB can be contacted
*/
SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException;
/**
* Closes all connections, if any.
* This is done in a synchronous (blocking) way.
*/
void close();
}

View File

@ -1,103 +1,103 @@
package meerkat.bulletinboard;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageOutputStream;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Collection;
/**
* Created by Arbel on 07/11/15.
*
* This interface refers to a single instance of a Bulletin Board
* An implementation of this interface may use any DB and be hosted on any machine.
*/
public interface BulletinBoardServer{
/**
* This method initializes the server by reading the signature data and storing it
* It also establishes the connection to the DB
* @throws CommunicationException on DB connection error
*/
public void init(String meerkatDB) throws CommunicationException;
/**
* Post a message to bulletin board.
* @param msg is the actual (signed) message
* @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form)
* @throws CommunicationException on DB connection error
*/
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException;
/**
* Read all messages posted matching the given filter
* @param filterList return only messages that match the filters (empty list or null means no filtering)
* @param out is an output stream into which the matching messages are written
* @throws CommunicationException on DB connection error
*/
public void readMessages(MessageFilterList filterList, MessageOutputStream<BulletinBoardMessage> out) throws CommunicationException;
/**
* Informs server about a new batch message
* @param message contains the required data about the new batch
* @return TRUE if the batch request is accepted amd FALSE otherwise
* Specifically, if such a batch already exists and is not yet closed: the value returned will be TRUE
* However, if such a batch exists and is already closed: the value returned will be FALSE
* @throws CommunicationException on DB connection error
*/
public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException;
/**
* Posts a (part of a) batch message to the bulletin board
* Note that the existence and contents of a batch message are not available for reading before the batch is finalized
* @param batchMessage contains the (partial) data this message carries as well as meta-data required in order to place the data
* in the correct position inside the correct batch
* @return TRUE if the message is accepted and successfully saved and FALSE otherwise
* Specifically, if the batch is already closed: the value returned will be FALSE
* However, requiring to open a batch before insertion of messages is implementation-dependent
* @throws CommunicationException on DB connection error
*/
public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException;
/**
* Attempts to close and finalize a batch message
* @param message contains the data necessary to close the batch; in particular: the signature for the batch
* @return TRUE if the batch was successfully closed, FALSE otherwise
* Specifically, if the signature is invalid or if some of the batch parts have not yet been submitted: the value returned will be FALSE
* @throws CommunicationException on DB connection error
*/
public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException;
/**
* Reads a batch message from the server (starting with the supplied position)
* @param message specifies the signer ID and the batch ID to read as well as an (optional) start position
* @param out is a stream of the ordered batch messages starting from the specified start position (if given) or from the beginning (if omitted)
* @throws CommunicationException on DB connection error
* @throws IllegalArgumentException if message does not specify a batch
*/
public void readBatch(BatchSpecificationMessage message, MessageOutputStream<BatchData> out) throws CommunicationException, IllegalArgumentException;
/**
* Create a SyncQuery to test against that corresponds with the current server state for a specific filter list
* @param generateSyncQueryParams defines the information needed to generate the query
* @return The generated SyncQuery
* @throws CommunicationException on DB connection error
*/
SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException;
/**
* Queries the database for sync status with respect to a given sync query
* @param syncQuery contains a succinct representation of states to compare to
* @return a SyncQueryResponse object containing the representation of the most recent state the database matches
* @throws CommunicationException
*/
public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException;
/**
* This method closes the connection to the DB
* @throws CommunicationException on DB connection error
*/
public void close() throws CommunicationException;
}
package meerkat.bulletinboard;
import meerkat.comm.CommunicationException;
import meerkat.comm.MessageOutputStream;
import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.Collection;
/**
* Created by Arbel on 07/11/15.
*
* This interface refers to a single instance of a Bulletin Board
* An implementation of this interface may use any DB and be hosted on any machine.
*/
public interface BulletinBoardServer{
/**
* This method initializes the server by reading the signature data and storing it
* It also establishes the connection to the DB
* @throws CommunicationException on DB connection error
*/
public void init(String meerkatDB) throws CommunicationException;
/**
* Post a message to bulletin board.
* @param msg is the actual (signed) message
* @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form)
* @throws CommunicationException on DB connection error
*/
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException;
/**
* Read all messages posted matching the given filter
* @param filterList return only messages that match the filters (empty list or null means no filtering)
* @param out is an output stream into which the matching messages are written
* @throws CommunicationException on DB connection error
*/
public void readMessages(MessageFilterList filterList, MessageOutputStream<BulletinBoardMessage> out) throws CommunicationException;
/**
* Informs server about a new batch message
* @param message contains the required data about the new batch
* @return TRUE if the batch request is accepted amd FALSE otherwise
* Specifically, if such a batch already exists and is not yet closed: the value returned will be TRUE
* However, if such a batch exists and is already closed: the value returned will be FALSE
* @throws CommunicationException on DB connection error
*/
public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException;
/**
* Posts a (part of a) batch message to the bulletin board
* Note that the existence and contents of a batch message are not available for reading before the batch is finalized
* @param batchMessage contains the (partial) data this message carries as well as meta-data required in order to place the data
* in the correct position inside the correct batch
* @return TRUE if the message is accepted and successfully saved and FALSE otherwise
* Specifically, if the batch is already closed: the value returned will be FALSE
* However, requiring to open a batch before insertion of messages is implementation-dependent
* @throws CommunicationException on DB connection error
*/
public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException;
/**
* Attempts to close and finalize a batch message
* @param message contains the data necessary to close the batch; in particular: the signature for the batch
* @return TRUE if the batch was successfully closed, FALSE otherwise
* Specifically, if the signature is invalid or if some of the batch parts have not yet been submitted: the value returned will be FALSE
* @throws CommunicationException on DB connection error
*/
public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException;
/**
* Reads a batch message from the server (starting with the supplied position)
* @param message specifies the signer ID and the batch ID to read as well as an (optional) start position
* @param out is a stream of the ordered batch messages starting from the specified start position (if given) or from the beginning (if omitted)
* @throws CommunicationException on DB connection error
* @throws IllegalArgumentException if message does not specify a batch
*/
public void readBatch(BatchSpecificationMessage message, MessageOutputStream<BatchData> out) throws CommunicationException, IllegalArgumentException;
/**
* Create a SyncQuery to test against that corresponds with the current server state for a specific filter list
* @param generateSyncQueryParams defines the information needed to generate the query
* @return The generated SyncQuery
* @throws CommunicationException on DB connection error
*/
SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException;
/**
* Queries the database for sync status with respect to a given sync query
* @param syncQuery contains a succinct representation of states to compare to
* @return a SyncQueryResponse object containing the representation of the most recent state the database matches
* @throws CommunicationException
*/
public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException;
/**
* This method closes the connection to the DB
* @throws CommunicationException on DB connection error
*/
public void close() throws CommunicationException;
}

View File

@ -0,0 +1,42 @@
package meerkat.comm;
import com.google.protobuf.Message;
import meerkat.protobuf.Comm;
/**
* A generic communication channel that supports point-to-point and broadcast operation
*/
public interface Channel {
/**
* Return the id of the channel's endpoint (this will be used as the source of message sent from the channel).
* @return
*/
public int getSourceId();
public interface ReceiverCallback {
public void receiveMessage(Comm.BroadcastMessage envelope);
}
/**
* sends a private message
* @param destUser destination user's identifier
* @param msg message
*/
public void sendMessage(int destUser, Message msg);
/**
* broadcasts a message to all parties (including the sender)
* @param msg message
*/
public void broadcastMessage(Message msg);
/**
* Register a callback to handle received messages.
* The callback is called in the <b>Channel</b> thread, so no long processing should
* occur in the callback method.
* @param callback
*/
public void registerReceiverCallback(ReceiverCallback callback);
}

View File

@ -1,36 +1,36 @@
package meerkat.comm;
/**
* Created by talm on 24/10/15.
*/
public class CommunicationException extends Exception {
/**
* Generated serial.
*/
private static final long serialVersionUID = 2279440129497891293L;
private String message;
/**
* Default constructor. To be used only if error type is unknown.
*/
public CommunicationException(){
message = "Unknown communication exception";
}
/**
* Constructor enabling specifying of an error message.
* @param errorMessage
*/
public CommunicationException(String errorMessage){
message = errorMessage;
}
/**
* @return the error message specified.
*/
public String getMessage(){
return message;
}
}
package meerkat.comm;
/**
* Created by talm on 24/10/15.
*/
public class CommunicationException extends Exception {
/**
* Generated serial.
*/
private static final long serialVersionUID = 2279440129497891293L;
private String message;
/**
* Default constructor. To be used only if error type is unknown.
*/
public CommunicationException(){
message = "Unknown communication exception";
}
/**
* Constructor enabling specifying of an error message.
* @param errorMessage
*/
public CommunicationException(String errorMessage){
message = errorMessage;
}
/**
* @return the error message specified.
*/
public String getMessage(){
return message;
}
}

View File

@ -113,7 +113,7 @@ public class ECElGamalEncryption implements Encryption {
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
Pair<ECPoint,ECPoint> originalCipher = new Pair<>(
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);

View File

@ -1,7 +1,7 @@
package meerkat.logging;
/**
* Created by talm on 25/10/15.
*/
public class LogVerifier {
}
package meerkat.logging;
/**
* Created by talm on 25/10/15.
*/
public class LogVerifier {
}

View File

@ -1,7 +1,7 @@
package meerkat.logging;
/**
* Created by talm on 25/10/15.
*/
public class Logger {
}
package meerkat.logging;
/**
* Created by talm on 25/10/15.
*/
public class Logger {
}

View File

@ -1,49 +1,49 @@
package meerkat.util;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.*;
import java.util.Comparator;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* This class implements a comparison between BulletinBoardMessage instances that disregards:
* 1. The entry number (since this can be different between database instances)
* 2. The order of the signatures
*/
public class BulletinBoardMessageComparator implements Comparator<BulletinBoardMessage> {
/**
* Compare the messages
* @param msg1
* @param msg2
* @return 0 if the messages are equivalent (see above) and -1 otherwise.
*/
@Override
public int compare(BulletinBoardMessage msg1, BulletinBoardMessage msg2) {
List<Signature> msg1Sigs = msg1.getSigList();
List<Signature> msg2Sigs = msg2.getSigList();
// Compare unsigned message
if (!msg1.getMsg().equals(msg2.getMsg())){
return -1;
}
// Compare signatures
if (msg1Sigs.size() != msg2Sigs.size()){
return -1;
}
for (Signature sig : msg1Sigs){
if (!msg2Sigs.contains(sig)) {
return -1;
}
}
return 0;
}
}
package meerkat.util;
import meerkat.protobuf.BulletinBoardAPI;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.*;
import java.util.Comparator;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* This class implements a comparison between BulletinBoardMessage instances that disregards:
* 1. The entry number (since this can be different between database instances)
* 2. The order of the signatures
*/
public class BulletinBoardMessageComparator implements Comparator<BulletinBoardMessage> {
/**
* Compare the messages
* @param msg1
* @param msg2
* @return 0 if the messages are equivalent (see above) and -1 otherwise.
*/
@Override
public int compare(BulletinBoardMessage msg1, BulletinBoardMessage msg2) {
List<Signature> msg1Sigs = msg1.getSigList();
List<Signature> msg2Sigs = msg2.getSigList();
// Compare unsigned message
if (!msg1.getMsg().equals(msg2.getMsg())){
return -1;
}
// Compare signatures
if (msg1Sigs.size() != msg2Sigs.size()){
return -1;
}
for (Signature sig : msg1Sigs){
if (!msg2Sigs.contains(sig)) {
return -1;
}
}
return 0;
}
}

View File

@ -1,26 +1,26 @@
package meerkat.util;
import com.google.protobuf.ByteString;
/**
* Convert to/from Hex
*/
public class Hex {
/**
* Encode a {@link ByteString} as a hex string.
* @param str
* @return
*/
public static String encode(ByteString str) {
StringBuilder s = new StringBuilder();
for (byte b : str) {
s.append(Integer.toHexString(((int) b) & 0xff));
}
return s.toString();
}
public static String encode(byte[] bytes) {
return encode(ByteString.copyFrom(bytes));
}
}
package meerkat.util;
import com.google.protobuf.ByteString;
/**
* Convert to/from Hex
*/
public class Hex {
/**
* Encode a {@link ByteString} as a hex string.
* @param str
* @return
*/
public static String encode(ByteString str) {
StringBuilder s = new StringBuilder();
for (byte b : str) {
s.append(Integer.toHexString(((int) b) & 0xff));
}
return s.toString();
}
public static String encode(byte[] bytes) {
return encode(ByteString.copyFrom(bytes));
}
}

View File

@ -27,4 +27,5 @@ public class TimestampComparator implements Comparator<Timestamp> {
}
}
}

View File

@ -1,70 +1,70 @@
package meerkat.voting;
import static meerkat.protobuf.Voting.*;
/**
* Created by talm on 25/10/15.
*/
public interface VotingBooth {
public interface UI {
/**
* Prepare UI for a new user.
*/
void votingBegin();
/**
* UI must physically commit to an encrypted (or Wombat style) ballot.
* (probably by printing)
*
* When commitment is complete, should ask voter to choose between
* cast and audit.
*
* Called by votingbooth thread.
*/
void commitToEncryptedBallot(EncryptedBallot ballot);
/**
* Finalize a vote for casting
* Called by votingbooth in case user decides to cast.
*/
void castVote();
/**
* Submit audit information and spoil vote.
* Called by votingbooth in case user decides to audit
* @param ballotSecrets
*/
void auditVote(BallotSecrets ballotSecrets);
}
/**
* Must be called before using any other method.
* @param globalParams global election parameters (e.g., global signing key, global encryption key)
* @param boothParams local parameters (e.g., private signature key for booth, randomness table?)
*/
void init(ElectionParams globalParams, BoothParams boothParams);
/**
* Called from UI thread when voter has finished making selection.
*
* Should encrypt ballot and commit.
* @param ballot
*/
void submitBallot(PlaintextBallot ballot);
/**
* UI calls this when the user cancels the voting process in the middle.
*/
void cancelBallot();
/**
* Called by UI thread after voter made choice to cast or audit ballot.
* @param castVote
*/
void voterCastOrAudit(boolean castVote);
}
package meerkat.voting;
import static meerkat.protobuf.Voting.*;
/**
* Created by talm on 25/10/15.
*/
public interface VotingBooth {
public interface UI {
/**
* Prepare UI for a new user.
*/
void votingBegin();
/**
* UI must physically commit to an encrypted (or Wombat style) ballot.
* (probably by printing)
*
* When commitment is complete, should ask voter to choose between
* cast and audit.
*
* Called by votingbooth thread.
*/
void commitToEncryptedBallot(EncryptedBallot ballot);
/**
* Finalize a vote for casting
* Called by votingbooth in case user decides to cast.
*/
void castVote();
/**
* Submit audit information and spoil vote.
* Called by votingbooth in case user decides to audit
* @param ballotSecrets
*/
void auditVote(BallotSecrets ballotSecrets);
}
/**
* Must be called before using any other method.
* @param globalParams global election parameters (e.g., global signing key, global encryption key)
* @param boothParams local parameters (e.g., private signature key for booth, randomness table?)
*/
void init(ElectionParams globalParams, BoothParams boothParams);
/**
* Called from UI thread when voter has finished making selection.
*
* Should encrypt ballot and commit.
* @param ballot
*/
void submitBallot(PlaintextBallot ballot);
/**
* UI calls this when the user cancels the voting process in the middle.
*/
void cancelBallot();
/**
* Called by UI thread after voter made choice to cast or audit ballot.
* @param castVote
*/
void voterCastOrAudit(boolean castVote);
}

View File

@ -1,171 +1,171 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
import 'google/protobuf/timestamp.proto';
message BoolMsg {
bool value = 1;
}
message IntMsg {
int32 value = 1;
}
message MessageID {
// The ID of a message for unique retrieval.
// Note that it is assumed that this ID is a function of the message itself.
bytes ID = 1;
}
message UnsignedBulletinBoardMessage {
// Optional tags describing message; Used for message retrieval
repeated string tag = 1;
// Timestamp of the message (as defined by client)
google.protobuf.Timestamp timestamp = 2;
// The actual content of the message
bytes data = 3;
}
message BulletinBoardMessage {
// Serial entry number of message in database
int64 entryNum = 1;
// Unsigned raw data of message
UnsignedBulletinBoardMessage msg = 2;
// Signature of message (and tags), excluding the entry number.
repeated meerkat.Signature sig = 3;
}
message BulletinBoardMessageList {
repeated BulletinBoardMessage message = 1;
}
enum FilterType {
MSG_ID = 0; // Match exact message ID
EXACT_ENTRY = 1; // Match exact entry number in database (chronological)
MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological)
MIN_ENTRY = 3; // Find all entries in database starting from specified entry number (chronological)
SIGNER_ID = 4; // Find all entries in database that correspond to specific signature (signer)
TAG = 5; // Find all entries in database that have a specific tag
AFTER_TIME = 6; // Find all entries in database that occurred on or after a given timestamp
BEFORE_TIME = 7; // Find all entries in database that occurred on or before a given timestamp
// NOTE: The MAX_MESSAGES filter must remain the last filter type
// This is because the condition it specifies in an SQL statement must come last in the statement
// Keeping it last here allows for easily sorting the filters and keeping the code general
MAX_MESSAGES = 8; // Return at most some specified number of messages
}
message MessageFilter {
FilterType type = 1;
oneof filter{
bytes id = 2;
int64 entry = 3;
string tag = 4;
int64 maxMessages = 5;
google.protobuf.Timestamp timestamp = 6;
}
}
message MessageFilterList {
// Combination of filters.
// To be implemented using intersection ("AND") operations.
repeated MessageFilter filter = 1;
}
// This message is used to start a batch transfer to the Bulletin Board Server
message BeginBatchMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
repeated string tag = 3; // Tags for the batch message
}
// This message is used to finalize and sign a batch transfer to the Bulletin Board Server
message CloseBatchMessage {
int32 batchId = 1; // Unique identifier for the batch (unique per signer)
int32 batchLength = 2; // Number of messages in the batch
google.protobuf.Timestamp timestamp = 3; // Timestamp of the batch (as defined by client)
meerkat.Signature sig = 4; // Signature on the (ordered) batch messages
}
// Container for single batch message data
message BatchData {
bytes data = 1;
}
// List of BatchData; Only used for testing
message BatchDataList {
repeated BatchData data = 1;
}
// These messages comprise a batch message
message BatchMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
int32 serialNum = 3; // Location of the message in the batch: starting from 0
BatchData data = 4; // Actual data
}
// This message defines which batch to read and from which location to start reading
message BatchSpecificationMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
int32 startPosition = 3; // Position in batch to start reading from
}
// This message is used to define a single query to the server to ascertain whether or not the server is synched with the client
// up till a specified timestamp
message SingleSyncQuery {
google.protobuf.Timestamp timeOfSync = 1;
int64 checksum = 2;
}
// This message defines a complete server sync query
message SyncQuery {
MessageFilterList filterList = 1;
repeated SingleSyncQuery query = 2;
}
// This message defines the required information for generation of a SyncQuery instance by the server
message GenerateSyncQueryParams {
// Defines the set of messages required
MessageFilterList filterList = 1;
// Defines the locations in the list of messages to calculate single sync queries for
// The values should be between 0.0 and 1.0 and define the location in fractions of the size of the message set
repeated float breakpointList = 2;
}
// This message defines the server's response format to a sync query
message SyncQueryResponse {
// Serial entry number of current last entry in database
// Set to zero (0) in case no query checksums match
int64 lastEntryNum = 1;
// Largest value of timestamp for which the checksums match
google.protobuf.Timestamp lastTimeOfSync = 2;
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
import 'google/protobuf/timestamp.proto';
message BoolMsg {
bool value = 1;
}
message IntMsg {
int32 value = 1;
}
message MessageID {
// The ID of a message for unique retrieval.
// Note that it is assumed that this ID is a function of the message itself.
bytes ID = 1;
}
message UnsignedBulletinBoardMessage {
// Optional tags describing message; Used for message retrieval
repeated string tag = 1;
// Timestamp of the message (as defined by client)
google.protobuf.Timestamp timestamp = 2;
// The actual content of the message
bytes data = 3;
}
message BulletinBoardMessage {
// Serial entry number of message in database
int64 entryNum = 1;
// Unsigned raw data of message
UnsignedBulletinBoardMessage msg = 2;
// Signature of message (and tags), excluding the entry number.
repeated meerkat.Signature sig = 3;
}
message BulletinBoardMessageList {
repeated BulletinBoardMessage message = 1;
}
enum FilterType {
MSG_ID = 0; // Match exact message ID
EXACT_ENTRY = 1; // Match exact entry number in database (chronological)
MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological)
MIN_ENTRY = 3; // Find all entries in database starting from specified entry number (chronological)
SIGNER_ID = 4; // Find all entries in database that correspond to specific signature (signer)
TAG = 5; // Find all entries in database that have a specific tag
AFTER_TIME = 6; // Find all entries in database that occurred on or after a given timestamp
BEFORE_TIME = 7; // Find all entries in database that occurred on or before a given timestamp
// NOTE: The MAX_MESSAGES filter must remain the last filter type
// This is because the condition it specifies in an SQL statement must come last in the statement
// Keeping it last here allows for easily sorting the filters and keeping the code general
MAX_MESSAGES = 8; // Return at most some specified number of messages
}
message MessageFilter {
FilterType type = 1;
oneof filter{
bytes id = 2;
int64 entry = 3;
string tag = 4;
int64 maxMessages = 5;
google.protobuf.Timestamp timestamp = 6;
}
}
message MessageFilterList {
// Combination of filters.
// To be implemented using intersection ("AND") operations.
repeated MessageFilter filter = 1;
}
// This message is used to start a batch transfer to the Bulletin Board Server
message BeginBatchMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
repeated string tag = 3; // Tags for the batch message
}
// This message is used to finalize and sign a batch transfer to the Bulletin Board Server
message CloseBatchMessage {
int32 batchId = 1; // Unique identifier for the batch (unique per signer)
int32 batchLength = 2; // Number of messages in the batch
google.protobuf.Timestamp timestamp = 3; // Timestamp of the batch (as defined by client)
meerkat.Signature sig = 4; // Signature on the (ordered) batch messages
}
// Container for single batch message data
message BatchData {
bytes data = 1;
}
// List of BatchData; Only used for testing
message BatchDataList {
repeated BatchData data = 1;
}
// These messages comprise a batch message
message BatchMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
int32 serialNum = 3; // Location of the message in the batch: starting from 0
BatchData data = 4; // Actual data
}
// This message defines which batch to read and from which location to start reading
message BatchSpecificationMessage {
bytes signerId = 1; // Unique signer identifier
int32 batchId = 2; // Unique identifier for the batch (unique per signer)
int32 startPosition = 3; // Position in batch to start reading from
}
// This message is used to define a single query to the server to ascertain whether or not the server is synched with the client
// up till a specified timestamp
message SingleSyncQuery {
google.protobuf.Timestamp timeOfSync = 1;
int64 checksum = 2;
}
// This message defines a complete server sync query
message SyncQuery {
MessageFilterList filterList = 1;
repeated SingleSyncQuery query = 2;
}
// This message defines the required information for generation of a SyncQuery instance by the server
message GenerateSyncQueryParams {
// Defines the set of messages required
MessageFilterList filterList = 1;
// Defines the locations in the list of messages to calculate single sync queries for
// The values should be between 0.0 and 1.0 and define the location in fractions of the size of the message set
repeated float breakpointList = 2;
}
// This message defines the server's response format to a sync query
message SyncQueryResponse {
// Serial entry number of current last entry in database
// Set to zero (0) in case no query checksums match
int64 lastEntryNum = 1;
// Largest value of timestamp for which the checksums match
google.protobuf.Timestamp lastTimeOfSync = 2;
}

View File

@ -0,0 +1,13 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message BroadcastMessage {
int32 sender = 1;
int32 destination = 2;
bool is_private = 3;
bytes payload = 5;
}

View File

@ -1,22 +1,22 @@
// Protobufs for specific crypto primitives
syntax = "proto3";
package meerkat;
import 'meerkat/crypto.proto';
option java_package = "meerkat.protobuf";
message ElGamalPublicKey {
// DER-encoded SubjectPublicKeyInfo as in RFC 3279
bytes subject_public_key_info = 1;
}
// An El-Gamal ciphertext
// Each group element should be an ASN.1 encoded curve point with compression.
message ElGamalCiphertext {
bytes c1 = 1; // First group element
bytes c2 = 2; // Second group element
// Protobufs for specific crypto primitives
syntax = "proto3";
package meerkat;
import 'meerkat/crypto.proto';
option java_package = "meerkat.protobuf";
message ElGamalPublicKey {
// DER-encoded SubjectPublicKeyInfo as in RFC 3279
bytes subject_public_key_info = 1;
}
// An El-Gamal ciphertext
// Each group element should be an ASN.1 encoded curve point with compression.
message ElGamalCiphertext {
bytes c1 = 1; // First group element
bytes c2 = 2; // Second group element
}

View File

@ -1,54 +1,54 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
enum SignatureType {
ECDSA = 0;
DSA = 1;
}
message BigInteger {
bytes data = 1;
}
// A digital signature
message Signature {
SignatureType type = 1;
// Data encoding depends on type; default is DER-encoded
bytes data = 2;
// ID of the signer (should be the fingerprint of the signature verification key)
bytes signer_id = 3;
}
// Public key used to verify signatures
message SignatureVerificationKey {
SignatureType type = 1;
// Data encoding depends on type; default is x509 DER-encoded
bytes data = 2;
}
// A public encryption key
message EncryptionPublicKey {
bytes data = 1;
}
// Randomness used for encryption
message EncryptionRandomness {
bytes data = 1;
}
// A proof that randomness is correctly generated
message RandomnessGenerationProof {
bytes data = 1;
}
// An encrypted message (rerandomizable)
message RerandomizableEncryptedMessage {
bytes data = 1;
}
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
enum SignatureType {
ECDSA = 0;
DSA = 1;
}
message BigInteger {
bytes data = 1;
}
// A digital signature
message Signature {
SignatureType type = 1;
// Data encoding depends on type; default is DER-encoded
bytes data = 2;
// ID of the signer (should be the fingerprint of the signature verification key)
bytes signer_id = 3;
}
// Public key used to verify signatures
message SignatureVerificationKey {
SignatureType type = 1;
// Data encoding depends on type; default is x509 DER-encoded
bytes data = 2;
}
// A public encryption key
message EncryptionPublicKey {
bytes data = 1;
}
// Randomness used for encryption
message EncryptionRandomness {
bytes data = 1;
}
// A proof that randomness is correctly generated
message RandomnessGenerationProof {
bytes data = 1;
}
// An encrypted message (rerandomizable)
message RerandomizableEncryptedMessage {
bytes data = 1;
}

View File

@ -1,12 +1,12 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
// TODO:
message ZeroKnowledgeProof {
bytes data = 1;
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto';
// TODO:
message ZeroKnowledgeProof {
bytes data = 1;
}

View File

@ -1,90 +1,90 @@
syntax = "proto3";
package meerkat;
import 'meerkat/crypto.proto';
option java_package = "meerkat.protobuf";
// A ballot question. This is an opaque
// data type that is parsed by the UI to display
// the question.
message BallotQuestion {
bytes data = 1;
}
// An answer to a specific ballot question.
// The answer is a vector of signed integers,
// to encompass voting schemes such as ranked voting
// and STV.
message BallotAnswer {
repeated sint64 answer = 1 [packed=true];
}
message PlaintextBallot {
uint64 serialNumber = 1; // Ballot serial number
repeated BallotAnswer answers = 2;
}
message EncryptedBallot {
uint64 serialNumber = 1; // Ballot serial number
RerandomizableEncryptedMessage data = 2;
}
message BallotSecrets {
PlaintextBallot plaintext_ballot = 1;
EncryptionRandomness encryption_randomness = 2;
RandomnessGenerationProof proof = 3;
}
message BoothParams {
repeated SignatureVerificationKey pscVerificationKeys = 1;
}
// A table to translate to and from compactly encoded answers
// and their human-understandable counterparts.
// This should be parsable by the UI
message BallotAnswerTranslationTable {
bytes data = 1;
}
// Data required in order to access the Bulletin Board Servers
message BulletinBoardClientParams {
// Addresses of all Bulletin Board Servers
repeated string bulletinBoardAddress = 1;
// Threshold fraction of successful servers posts before a post task is considered complete
float minRedundancy = 2;
}
message ElectionParams {
// TODO: different sets of keys for different roles?
repeated SignatureVerificationKey trusteeVerificationKeys = 1;
// How many trustees must participate in a signature for it to be considered valid.
uint32 trusteeSignatureThreshold = 2;
// The key used to encrypt ballots. The corresponding private key
// is shared between the trustees.
EncryptionPublicKey ballotEncryptionKey = 3;
// Verification keys for valid mixers.
repeated SignatureVerificationKey mixerVerificationKeys = 4;
// How many mixers must participate for the mixing to be considered valid
uint32 mixerThreshold = 5;
// Candidate list (or other question format)
repeated BallotQuestion questions = 6;
// Translation table between answers and plaintext encoding
BallotAnswerTranslationTable answerTranslationTable = 7;
// Data required in order to access the Bulletin Board Servers
BulletinBoardClientParams bulletinBoardClientParams = 8;
}
syntax = "proto3";
package meerkat;
import 'meerkat/crypto.proto';
option java_package = "meerkat.protobuf";
// A ballot question. This is an opaque
// data type that is parsed by the UI to display
// the question.
message BallotQuestion {
bytes data = 1;
}
// An answer to a specific ballot question.
// The answer is a vector of signed integers,
// to encompass voting schemes such as ranked voting
// and STV.
message BallotAnswer {
repeated sint64 answer = 1 [packed=true];
}
message PlaintextBallot {
uint64 serialNumber = 1; // Ballot serial number
repeated BallotAnswer answers = 2;
}
message EncryptedBallot {
uint64 serialNumber = 1; // Ballot serial number
RerandomizableEncryptedMessage data = 2;
}
message BallotSecrets {
PlaintextBallot plaintext_ballot = 1;
EncryptionRandomness encryption_randomness = 2;
RandomnessGenerationProof proof = 3;
}
message BoothParams {
repeated SignatureVerificationKey pscVerificationKeys = 1;
}
// A table to translate to and from compactly encoded answers
// and their human-understandable counterparts.
// This should be parsable by the UI
message BallotAnswerTranslationTable {
bytes data = 1;
}
// Data required in order to access the Bulletin Board Servers
message BulletinBoardClientParams {
// Addresses of all Bulletin Board Servers
repeated string bulletinBoardAddress = 1;
// Threshold fraction of successful servers posts before a post task is considered complete
float minRedundancy = 2;
}
message ElectionParams {
// TODO: different sets of keys for different roles?
repeated SignatureVerificationKey trusteeVerificationKeys = 1;
// How many trustees must participate in a signature for it to be considered valid.
uint32 trusteeSignatureThreshold = 2;
// The key used to encrypt ballots. The corresponding private key
// is shared between the trustees.
EncryptionPublicKey ballotEncryptionKey = 3;
// Verification keys for valid mixers.
repeated SignatureVerificationKey mixerVerificationKeys = 4;
// How many mixers must participate for the mixing to be considered valid
uint32 mixerThreshold = 5;
// Candidate list (or other question format)
repeated BallotQuestion questions = 6;
// Translation table between answers and plaintext encoding
BallotAnswerTranslationTable answerTranslationTable = 7;
// Data required in order to access the Bulletin Board Servers
BulletinBoardClientParams bulletinBoardClientParams = 8;
}

View File

@ -1,46 +1,46 @@
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.filter.ThresholdFilter
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.util.Duration
import static ch.qos.logback.classic.Level.*
if (System.getProperty("log.debug") != null) {
println "Logback configuration debugging enabled"
statusListener(OnConsoleStatusListener)
}
def LOG_LEVEL = toLevel(System.getProperty("log.level"), INFO)
def haveBeagle = System.getProperty("log.beagle") != null
def logOps = System.getProperty("log.ops") != null
appender("CONSOLE", ConsoleAppender) {
filter(ThresholdFilter) {
level = toLevel(System.getProperty("log.level"), TRACE)
}
encoder(PatternLayoutEncoder) {
pattern = "%d{HH:mm:ss.SSS} [%thread %file:%line] %-5level %logger{0} - %msg%n"
}
}
def appenders = [ "CONSOLE" ]
if (haveBeagle) {
appender("SOCKET", SocketAppender) {
includeCallerData = true
remoteHost = "localhost"
port = 4321
reconnectionDelay = new Duration(10000)
}
appenders += ["SOCKET"]
}
root(LOG_LEVEL, appenders)
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.filter.ThresholdFilter
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.util.Duration
import static ch.qos.logback.classic.Level.*
if (System.getProperty("log.debug") != null) {
println "Logback configuration debugging enabled"
statusListener(OnConsoleStatusListener)
}
def LOG_LEVEL = toLevel(System.getProperty("log.level"), INFO)
def haveBeagle = System.getProperty("log.beagle") != null
def logOps = System.getProperty("log.ops") != null
appender("CONSOLE", ConsoleAppender) {
filter(ThresholdFilter) {
level = toLevel(System.getProperty("log.level"), TRACE)
}
encoder(PatternLayoutEncoder) {
pattern = "%d{HH:mm:ss.SSS} [%thread %file:%line] %-5level %logger{0} - %msg%n"
}
}
def appenders = [ "CONSOLE" ]
if (haveBeagle) {
appender("SOCKET", SocketAppender) {
includeCallerData = true
remoteHost = "localhost"
port = 4321
reconnectionDelay = new Duration(10000)
}
appenders += ["SOCKET"]
}
root(LOG_LEVEL, appenders)

View File

@ -0,0 +1,96 @@
package meerkat.comm;
import com.google.protobuf.Message;
import com.google.protobuf.TextFormat;
import meerkat.protobuf.Comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;
import java.util.concurrent.*;
/**
* Created by Tzlil on 2/14/2016.
*/
// TODO: Change nane to network
public class ChannelImpl {
final Logger logger = LoggerFactory.getLogger(getClass());
//private ExecutorService executorService = Executors.newCachedThreadPool();
public static int BROADCAST = 0;
Map<Integer,SingleChannel> channels = new TreeMap<>();
public ChannelImpl() {
}
public Channel getChannel(int id) {
return new SingleChannel(id);
}
public class SingleChannel implements Channel {
protected final int id;
ReceiverCallback callback;
SingleChannel(int id) {
this.id = id;
channels.put(id, this);
}
@Override
public int getSourceId() {
return id;
}
@Override
public void sendMessage(int destUser, Message msg) {
if (destUser < 1)
return;
SingleChannel channel = channels.get(destUser);
if (channel == null) {
logger.warn("Party {} attempting to send message to non-existing party {}", getSourceId(), destUser);
return;
}
Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder()
.setSender(id)
.setDestination(destUser)
.setIsPrivate(true)
.setPayload(msg.toByteString())
.build();
logger.debug("sending Message: Dst={},Src={} [{}]", broadcastMessage.getDestination(),
broadcastMessage.getSender(), TextFormat.printToString(msg));
channel.callback.receiveMessage(broadcastMessage);
}
@Override
public void broadcastMessage(Message msg) {
Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder()
.setSender(id)
.setDestination(BROADCAST)
.setIsPrivate(false)
.setPayload(msg.toByteString())
.build();
logger.debug("broadcasting Message: Src={} [{}]",
broadcastMessage.getSender(), TextFormat.printToString(msg));
for (SingleChannel channel : channels.values()) {
channel.callback.receiveMessage(broadcastMessage);
}
}
@Override
public void registerReceiverCallback(final ReceiverCallback callback) {
this.callback = callback;
}
}
}

View File

@ -3,7 +3,6 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.crypto.concrete.ECDSASignature;
import meerkat.protobuf.Crypto;
import org.junit.Test;

View File

@ -3,7 +3,6 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.protobuf.Crypto;
import meerkat.crypto.concrete.ECDSASignature;
import org.junit.Before;
import org.junit.Test;

View File

@ -1,6 +1,6 @@
Certs and private keys for testing generated using OpenSSL
.crt and .pem files are in PEM format
.der files are in binary DER format
files that have a name of the form *-with-password-xxxx.pem are encrypted with the password xxxx
Certs and private keys for testing generated using OpenSSL
.crt and .pem files are in PEM format
.der files are in binary DER format
files that have a name of the form *-with-password-xxxx.pem are encrypted with the password xxxx

View File

@ -1,8 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,243D718A0D80C59590E582A26E87A49C
RG6ITUTIdbJdWYX57oMn3tTCzHJSTjXAIZLjoVxy/v4UFYjluaFhGonIlbH1q2pP
ueu29Q3eT6144ypB8ARUJ1x0kRX1OL9zNHgdF9ulrCf9/nhGyC2nL+tHZ0YPbxoQ
+6yCQcRWvjUXLVzPEUnwMuHXJDpaXES8X0R4CISQKIA=
-----END EC PRIVATE KEY-----
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,243D718A0D80C59590E582A26E87A49C
RG6ITUTIdbJdWYX57oMn3tTCzHJSTjXAIZLjoVxy/v4UFYjluaFhGonIlbH1q2pP
ueu29Q3eT6144ypB8ARUJ1x0kRX1OL9zNHgdF9ulrCf9/nhGyC2nL+tHZ0YPbxoQ
+6yCQcRWvjUXLVzPEUnwMuHXJDpaXES8X0R4CISQKIA=
-----END EC PRIVATE KEY-----

View File

@ -1,5 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQge8JqCoaLoZq61aQki5Xm
GppcfAAkhHDGNQw/wLof5LmhRANCAAQJD1kW6BsNkRY9tslaugpOJOaoKX4uBz4S
Q96lPaPWkatNVgQchwNeB/hdjZwNuwE7A7XAwr69HFmhXRhsM005
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQge8JqCoaLoZq61aQki5Xm
GppcfAAkhHDGNQw/wLof5LmhRANCAAQJD1kW6BsNkRY9tslaugpOJOaoKX4uBz4S
Q96lPaPWkatNVgQchwNeB/hdjZwNuwE7A7XAwr69HFmhXRhsM005
-----END PRIVATE KEY-----

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugbDZEWPbbJWroKTiTmqCl+Lgc+
EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+vRxZoV0YbDNNOQ==
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugbDZEWPbbJWroKTiTmqCl+Lgc+
EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+vRxZoV0YbDNNOQ==
-----END PUBLIC KEY-----

View File

@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFjCCArygAwIBAgICEAAwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MTM1NFoXDTI1MTEwODE2MTM1
NFowbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDExEzARBgNVBAgMClNvbWUt
U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugb
DZEWPbbJWroKTiTmqCl+Lgc+EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+
vRxZoV0YbDNNOaOCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFLamS8o2
hFNd0vWy/irEBNWVNwFXMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
A0gAMEUCIQD6QbhNNmB3AVVqhmXuiLA7WF6raShw6n0g/VloVGQebQIgEvxYclpO
MMynt5wH6X65rtn4Q1EGaDMvNbFweCDsldk=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDFjCCArygAwIBAgICEAAwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MTM1NFoXDTI1MTEwODE2MTM1
NFowbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDExEzARBgNVBAgMClNvbWUt
U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugb
DZEWPbbJWroKTiTmqCl+Lgc+EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+
vRxZoV0YbDNNOaOCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFLamS8o2
hFNd0vWy/irEBNWVNwFXMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
A0gAMEUCIQD6QbhNNmB3AVVqhmXuiLA7WF6raShw6n0g/VloVGQebQIgEvxYclpO
MMynt5wH6X65rtn4Q1EGaDMvNbFweCDsldk=
-----END CERTIFICATE-----

View File

@ -1,9 +1,9 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBOjCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMTBW
MBAGByqGSM49AgEGBSuBBAAKA0IABAkPWRboGw2RFj22yVq6Ck4k5qgpfi4HPhJD
3qU9o9aRq01WBByHA14H+F2NnA27ATsDtcDCvr0cWaFdGGwzTTmgADAKBggqhkjO
PQQDAgNIADBFAiEA8gmIhALr7O5M1QLReGH3jheildTIr1mDWl14WyMf9U4CIF23
mInyo4VqNHLzxMLg5Cn3Oddokng3OXa63y4nTfv+
-----END CERTIFICATE REQUEST-----
-----BEGIN CERTIFICATE REQUEST-----
MIIBOjCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMTBW
MBAGByqGSM49AgEGBSuBBAAKA0IABAkPWRboGw2RFj22yVq6Ck4k5qgpfi4HPhJD
3qU9o9aRq01WBByHA14H+F2NnA27ATsDtcDCvr0cWaFdGGwzTTmgADAKBggqhkjO
PQQDAgNIADBFAiEA8gmIhALr7O5M1QLReGH3jheildTIr1mDWl14WyMf9U4CIF23
mInyo4VqNHLzxMLg5Cn3Oddokng3OXa63y4nTfv+
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgYpBEO+XWm/n6VPeMVK76
mrZkDTpiwLsDykG7M4fU5RKhRANCAAR71/kVGyA3hdxcLBBT3NPQF6R3LholmLRN
qhnvHqzJWuy7ev+Xbuxtt9AN0ajyeFDy8Oe1bUSidnLyQi+nXC0f
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgYpBEO+XWm/n6VPeMVK76
mrZkDTpiwLsDykG7M4fU5RKhRANCAAR71/kVGyA3hdxcLBBT3NPQF6R3LholmLRN
qhnvHqzJWuy7ev+Xbuxtt9AN0ajyeFDy8Oe1bUSidnLyQi+nXC0f
-----END PRIVATE KEY-----

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsgN4XcXCwQU9zT0Bekdy4aJZi0
TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1EonZy8kIvp1wtHw==
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsgN4XcXCwQU9zT0Bekdy4aJZi0
TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1EonZy8kIvp1wtHw==
-----END PUBLIC KEY-----

View File

@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFjCCArygAwIBAgICEAEwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MjAzM1oXDTI1MTEwODE2MjAz
M1owbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDIxEzARBgNVBAgMClNvbWUt
U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsg
N4XcXCwQU9zT0Bekdy4aJZi0TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1E
onZy8kIvp1wtH6OCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKCdquYj
DGHqAHt+4PIDlw0h2UvuMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
A0gAMEUCIQDpo5B0vvEJSax3YzOMfE8l0pfDUIKLdBWJVGeq0VLtIgIgVr0+4/0e
n+R+l1OVOLh2GirloOgbv5Ch5BQ2pQNAG2Y=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDFjCCArygAwIBAgICEAEwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MjAzM1oXDTI1MTEwODE2MjAz
M1owbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDIxEzARBgNVBAgMClNvbWUt
U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsg
N4XcXCwQU9zT0Bekdy4aJZi0TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1E
onZy8kIvp1wtH6OCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKCdquYj
DGHqAHt+4PIDlw0h2UvuMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
A0gAMEUCIQDpo5B0vvEJSax3YzOMfE8l0pfDUIKLdBWJVGeq0VLtIgIgVr0+4/0e
n+R+l1OVOLh2GirloOgbv5Ch5BQ2pQNAG2Y=
-----END CERTIFICATE-----

View File

@ -1,9 +1,9 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBOzCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMjBW
MBAGByqGSM49AgEGBSuBBAAKA0IABHvX+RUbIDeF3FwsEFPc09AXpHcuGiWYtE2q
Ge8erMla7Lt6/5du7G230A3RqPJ4UPLw57VtRKJ2cvJCL6dcLR+gADAKBggqhkjO
PQQDAgNJADBGAiEA6Ls/ojRaZT+u4YeOBYcPbRcJE3jSTe1Sm/lR7fDyEhMCIQCk
UOca+e2b8+CqM3CURBv6TqUMmZ3HeMRvEAxFPqOWSw==
-----END CERTIFICATE REQUEST-----
-----BEGIN CERTIFICATE REQUEST-----
MIIBOzCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMjBW
MBAGByqGSM49AgEGBSuBBAAKA0IABHvX+RUbIDeF3FwsEFPc09AXpHcuGiWYtE2q
Ge8erMla7Lt6/5du7G230A3RqPJ4UPLw57VtRKJ2cvJCL6dcLR+gADAKBggqhkjO
PQQDAgNJADBGAiEA6Ls/ojRaZT+u4YeOBYcPbRcJE3jSTe1Sm/lR7fDyEhMCIQCk
UOca+e2b8+CqM3CURBv6TqUMmZ3HeMRvEAxFPqOWSw==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIBGjCBw6ADAgECAgEBMAkGByqGSM49BAEwEDEOMAwGA1UEAxMFY2VydDEwHhcN
MTUxMTI4MTEwNDAwWhcNMTYxMTI4MTEwNDAwWjAQMQ4wDAYDVQQDEwVjZXJ0MTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABLiyFMVWQtFi4fCjOGLDwQcdjyr48Y8j
P+eLEIGMYKKv8bqL3Vchs0iOPoyGH6jxYj2/ShnLSIEuIMPfVgV9kxSjDzANMAsG
A1UdDwQEAwIHgDAJBgcqhkjOPQQBA0cAMEQCIH7R0AWO0AYiHOs+QsHEpWiebFc1
cyxCKJGkf8KA1KJrAiArCia7PWl0KzaqA0RQC4J0BKp4rZo1PCqKI8DirKQf/Q==
-----END CERTIFICATE-----

Some files were not shown because too many files have changed in this diff Show More