From b17954adc29df3fe14839695a3c6d4ca7d60b188 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 14 Dec 2015 23:14:52 +0200 Subject: [PATCH 001/106] Split interface into BulletinBoardClient and AsyncBulletinBoardClient. Added Batch Messages Bulletin Board Client interface and associated ProtoBufs. Returned simple implementation of BulletinBoardClient. Made ThreadedBulletinBoardClient extend SimpleBulletinBoardClient. Fixed an issue in SQLite where identical Signatures could be added to the same message. --- .../SimpleBulletinBoardClient.java | 32 +++++----- .../ThreadedBulletinBoardClient.java | 45 +++++++------- .../BulletinBoardClientIntegrationTest.java | 3 +- .../sqlserver/SQLiteQueryProvider.java | 3 +- .../AsyncBulletinBoardClient.java | 62 +++++++++++++++++++ .../bulletinboard/BulletinBoardClient.java | 23 ++++--- .../meerkat/bulletinboard/SignedBatch.java | 50 +++++++++++++++ .../main/proto/meerkat/BulletinBoardAPI.proto | 27 ++++++++ 8 files changed, 196 insertions(+), 49 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index f340cae..4244f15 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -5,8 +5,7 @@ import meerkat.comm.CommunicationException; import meerkat.crypto.Digest; import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Voting; -import meerkat.protobuf.Voting.BulletinBoardClientParams; +import meerkat.protobuf.Voting.*; import meerkat.rest.*; import java.util.List; @@ -19,23 +18,24 @@ import javax.ws.rs.core.Response; /** * Created by Arbel Deutsch Peled on 05-Dec-15. + * Implements BulletinBoardClient interface in a simple, straightforward manner */ -public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { +public class SimpleBulletinBoardClient implements BulletinBoardClient{ - private List meerkatDBs; + protected List meerkatDBs; - private Client client; + protected Client client; - private Digest digest; + 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(Voting.BulletinBoardClientParams clientParams) { + @Override + public void init(BulletinBoardClientParams clientParams) { - meerkatDBs = clientParams.getBulletinBoardAddressList(); + this.meerkatDBs = clientParams.getBulletinBoardAddressList(); client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); @@ -52,7 +52,7 @@ public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { * @return the message ID for later retrieval * @throws CommunicationException */ -// @Override + @Override public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { WebTarget webTarget; @@ -88,7 +88,7 @@ public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { * @param id is the requested message ID * @return the number of DBs in which retrieval was successful */ -// @Override + @Override public float getRedundancy(MessageID id) { WebTarget webTarget; Response response; @@ -125,7 +125,7 @@ public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering). * @return */ -// @Override + @Override public List readMessages(MessageFilterList filterList) { WebTarget webTarget; Response response; @@ -154,8 +154,8 @@ public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { return null; } -// @Override -// public void registerNewMessageCallback(MessageCallback callback, MessageFilterList filterList) { -// callback.handleNewMessage(readMessages(filterList)); -// } + public void close() { + client.close(); + } + } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index bb46c32..dd103c6 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -6,10 +6,8 @@ import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; import java.util.List; import java.util.concurrent.Executors; @@ -17,22 +15,16 @@ import java.util.concurrent.TimeUnit; /** * Created by Arbel Deutsch Peled on 05-Dec-15. - * Thread-based implementation of a Bulletin Board Client. + * Thread-based implementation of a Async Bulletin Board Client. * Features: * 1. Handles tasks concurrently. * 2. Retries submitting */ -public class ThreadedBulletinBoardClient implements BulletinBoardClient { +public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient { private final static int THREAD_NUM = 10; ListeningExecutorService listeningExecutor; - private Digest digest; - - private List meerkatDBs; - private String postSubAddress; - private String readSubAddress; - private final static int READ_MESSAGES_RETRY_NUM = 1; private int minAbsoluteRedundancy; @@ -44,15 +36,13 @@ public class ThreadedBulletinBoardClient implements BulletinBoardClient { * @param clientParams contains the required information */ @Override - public void init(Voting.BulletinBoardClientParams clientParams) { + public void init(BulletinBoardClientParams clientParams) { - meerkatDBs = clientParams.getBulletinBoardAddressList(); + super.init(clientParams); - minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * meerkatDBs.size()); + minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * clientParams.getBulletinBoardAddressCount()); - listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUM)); - - digest = new SHA256Digest(); + listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUM)); } @@ -78,13 +68,21 @@ public class ThreadedBulletinBoardClient implements BulletinBoardClient { return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); } + @Override + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback) { + return null; //TODO: Implement + } + + @Override + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + return null; //TODO: Implement + } + /** * 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 void getRedundancy(MessageID id, ClientCallback callback) { @@ -101,8 +99,6 @@ public class ThreadedBulletinBoardClient implements BulletinBoardClient { * 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 */ @Override public void readMessages(MessageFilterList filterList, ClientCallback> callback) { @@ -116,8 +112,15 @@ public class ThreadedBulletinBoardClient implements BulletinBoardClient { } + @Override + public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { + // TODO: Implement + } + @Override public void close() { + super.close(); + try { listeningExecutor.shutdown(); while (! listeningExecutor.isShutdown()) { diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index dda76c7..c090c92 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -1,4 +1,5 @@ import com.google.protobuf.ByteString; +import meerkat.bulletinboard.AsyncBulletinBoardClient; import meerkat.bulletinboard.BulletinBoardClient; import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; import meerkat.bulletinboard.ThreadedBulletinBoardClient; @@ -97,7 +98,7 @@ public class BulletinBoardClientIntegrationTest { } } - private BulletinBoardClient bulletinBoardClient; + private AsyncBulletinBoardClient bulletinBoardClient; private PostCallback postCallback; private RedundancyCallback redundancyCallback; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index 945ae47..8131d2b 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -98,10 +98,9 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi + " 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))"); + + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), UNIQUE(SignerId, 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)"); return list; } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java new file mode 100644 index 0000000..04b7a06 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -0,0 +1,62 @@ +package meerkat.bulletinboard; + +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 14-Dec-15. + */ +public interface AsyncBulletinBoardClient extends BulletinBoardClient { + + /** + * Post a message to the bulletin board in an asynchronous manner + * @param msg is the message to be posted + * @param callback is a class containing methods to handle the result of the operation + * @return a unique message ID for the message, that can be later used to retrieve the batch + */ + MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + + /** + * This method allows for sending large messages as a batch to the bulletin board + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param batchDataList is the (canonically ordered) list of data comprising the batch message + * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) + * @param callback is a callback function class for handling results of the operation + * @return a unique message ID for the entire message, that can be later used to retrieve the batch + */ + MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatch method in which startPosition is set to the default value 0 + */ + MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + + /** + * Check how "safe" a given message is in an asynchronous manner + * The result of the computation is a rank between 0.0 and 1.0 indicating the fraction of servers containing the message + * @param id is the unique message identifier for retrieval + * @param callback is a callback function class for handling results of the operation + */ + void getRedundancy(MessageID id, ClientCallback callback); + + /** + * Read all messages posted matching the given filter in an asynchronous 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). + * @param callback is a callback function class for handling results of the operation + */ + void readMessages(MessageFilterList filterList, ClientCallback> callback); + + /** + * Read a given batch message from the bulletin board + * @param signerId is the ID of the signer (sender) of the batch message + * @param batchId is the unique (per signer) ID of the batch + * @param callback is a callback class for handling the result of the operation + */ + void readBatch(byte[] signerId, int batchId, ClientCallback callback); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index c51e561..dcf6b15 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard; -import meerkat.comm.*; +import meerkat.comm.CommunicationException; import meerkat.protobuf.Voting.*; import static meerkat.protobuf.BulletinBoardAPI.*; @@ -24,26 +24,31 @@ public interface BulletinBoardClient { void init(BulletinBoardClientParams clientParams); /** - * Post a message to the bulletin board - * @param msg + * 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, ClientCallback callback); + MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; + + /** - * Check how "safe" a given message is - * @param id + * 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) */ - void getRedundancy(MessageID id, ClientCallback callback); + float getRedundancy(MessageID id); /** - * Read all messages posted matching the given filter + * 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 */ - void readMessages(MessageFilterList filterList, ClientCallback> callback); + List readMessages(MessageFilterList filterList); /** * Closes all connections, if any. diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java new file mode 100644 index 0000000..46cf07e --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java @@ -0,0 +1,50 @@ +package meerkat.bulletinboard; + +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.*; + +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 14-Dec-15. + * + * A data structure for holding both a batch message and its signature + */ +public class SignedBatch { + + private List batchDataList; + private Signature signature; + + public SignedBatch() { + batchDataList = new LinkedList(); + } + + public SignedBatch(List newDataList) { + this(); + appendBatchData(newDataList); + } + + public SignedBatch(List newDataList, Signature newSignature) { + this(newDataList); + signature = newSignature; + } + + public List getBatchDataList() { + return batchDataList; + } + + public Signature getSignature() { + return signature; + } + + public void appendBatchData(BatchData newBatchData) { + batchDataList.add(newBatchData); + } + + public void appendBatchData(List newBatchDataList) { + batchDataList.addAll(newBatchDataList); + } + + +} diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 0fe35f8..1a0bab1 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -77,4 +77,31 @@ message MessageFilterList { // 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 + meerkat.Signature sig = 3; // Signature on the (ordered) batch messages +} + +// Container for single batch message data +message BatchData { + bytes 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 } \ No newline at end of file From 37fdc0bb83d9e8a14a54c960cb915d513dfd4766 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Fri, 18 Dec 2015 14:39:40 +0200 Subject: [PATCH 002/106] Fixed minor H2 bug. Fixed dbTest gradle task (now tests all 3 supported DB engines). --- .../BulletinBoardClientIntegrationTest.java | 20 ++++++++--------- bulletin-board-server/build.gradle | 6 +++-- .../sqlserver/H2QueryProvider.java | 2 +- .../sqlserver/SQLiteQueryProvider.java | 22 ++++++++++++++++--- .../src/main/webapp/WEB-INF/web.xml | 2 +- 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index c090c92..55f0343 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -27,6 +27,12 @@ public class BulletinBoardClientIntegrationTest { Semaphore jobSemaphore; Vector thrown; + protected void genericHandleFailure(Throwable t){ + System.err.println(t.getCause() + " " + t.getMessage()); + thrown.add(t); + jobSemaphore.release(); + } + private class PostCallback implements ClientCallback{ @Override @@ -37,8 +43,7 @@ public class BulletinBoardClientIntegrationTest { @Override public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); + genericHandleFailure(t); } } @@ -59,8 +64,7 @@ public class BulletinBoardClientIntegrationTest { @Override public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); + genericHandleFailure(t); } } @@ -93,8 +97,7 @@ public class BulletinBoardClientIntegrationTest { @Override public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); + genericHandleFailure(t); } } @@ -202,10 +205,7 @@ public class BulletinBoardClientIntegrationTest { } bulletinBoardClient.close(); - - for (Throwable t : thrown) { - System.err.println(t.getMessage()); - } + if (thrown.size() > 0) { assert false; } diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index eb197c9..62e4b0c 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -75,13 +75,15 @@ dependencies { test { exclude '**/*SQLite*Test*' exclude '**/*H2*Test*' - exclude '**/*MySql*Test' + exclude '**/*MySQL*Test*' exclude '**/*IntegrationTest*' } task dbTest(type: Test) { include '**/*H2*Test*' - include '**/*MySql*Test' + include '**/*MySQL*Test*' + include '**/*SQLite*Test*' + outputs.upToDateWhen { false } } task integrationTest(type: Test) { diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index fa2b146..d76601f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -74,7 +74,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider case MAX_MESSAGES: return "LIMIT :Limit" + serialString; case MSG_ID: - return "MsgTable.MsgId = MsgId" + serialString; + return "MsgTable.MsgId = :MsgId" + serialString; case SIGNER_ID: return "EXISTS (SELECT 1 FROM SignatureTable" + " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)"; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index 8131d2b..d796789 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -73,15 +73,31 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi @Override public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException { - return null; //TODO: write this. + + switch(filterType) { + case EXACT_ENTRY: // Go through + case MAX_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() { - // TODO: Fix this + SQLiteDataSource dataSource = new SQLiteDataSource(); dataSource.setUrl("jdbc:sqlite:" + dbName); - dataSource.setDatabaseName("meerkat"); //TODO: Make generic return dataSource; } diff --git a/bulletin-board-server/src/main/webapp/WEB-INF/web.xml b/bulletin-board-server/src/main/webapp/WEB-INF/web.xml index 2198c07..226aa3b 100644 --- a/bulletin-board-server/src/main/webapp/WEB-INF/web.xml +++ b/bulletin-board-server/src/main/webapp/WEB-INF/web.xml @@ -31,7 +31,7 @@ mypass dbType - SQLite + H2 meerkat.bulletinboard.webapp.BulletinBoardWebApp From 37f962d520d9555e6336f8d27a1b34c89c71b019 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sat, 19 Dec 2015 19:54:50 +0200 Subject: [PATCH 003/106] Defined semi-final versions of the batch interfaces. Implemented in part extended BB Server interface. Added Digest support for Batch messages. Made GlobalCryptoSetup a final singleton. --- .../ThreadedBulletinBoardClient.java | 5 + .../callbacks/ClientFutureCallback.java | 6 - .../GetRedundancyFutureCallback.java | 6 +- .../callbacks/PostMessageFutureCallback.java | 8 +- .../callbacks/ReadMessagesFutureCallback.java | 9 +- .../BulletinBoardClientIntegrationTest.java | 3 +- .../sqlserver/BulletinBoardSQLServer.java | 203 +++++++++++++++--- .../sqlserver/MySQLQueryProvider.java | 80 ++++++- .../sqlserver/mappers/BatchDataMapper.java | 21 ++ .../{EntryNumMapper.java => LongMapper.java} | 2 +- .../webapp/BulletinBoardWebApp.java | 59 ++++- .../AsyncBulletinBoardClient.java | 28 ++- .../bulletinboard/BulletinBoardClient.java | 5 - .../bulletinboard/BulletinBoardServer.java | 73 +++++-- .../main/java/meerkat/crypto/BatchDigest.java | 20 ++ .../src/main/java/meerkat/crypto/Digest.java | 6 +- .../crypto/concrete/ECDSASignature.java | 5 +- .../crypto/concrete/ECElGamalEncryption.java | 5 +- .../crypto/concrete/GenericBatchDigest.java | 27 +++ .../crypto/concrete/GlobalCryptoSetup.java | 28 ++- .../meerkat/crypto/concrete/SHA256Digest.java | 3 +- .../main/proto/meerkat/BulletinBoardAPI.proto | 7 + .../crypto/concrete/ECElGamalUtils.java | 5 +- .../src/main/java/meerkat/rest/Constants.java | 4 + 24 files changed, 516 insertions(+), 102 deletions(-) create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java rename bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/{EntryNumMapper.java => LongMapper.java} (87%) create mode 100644 meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java create mode 100644 meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index dd103c6..5953bde 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -117,6 +117,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple // TODO: Implement } + @Override + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) { + // TODO: Implement + } + @Override public void close() { super.close(); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java index 7c5b7b0..54cc63a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java @@ -1,14 +1,8 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinClientJob; import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; /** * This is a future callback used to listen to workers and run on job finish diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java index 518ed77..719428f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java @@ -1,7 +1,7 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.protobuf.BulletinBoardAPI.*; @@ -13,10 +13,10 @@ import java.util.List; */ public class GetRedundancyFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback callback; + private ClientCallback callback; public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { + ClientCallback callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java index 221ae1a..abd4247 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java @@ -2,13 +2,11 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJob; import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; -import java.util.List; /** * This is a future callback used to listen to workers and run on job finish @@ -16,10 +14,10 @@ import java.util.List; */ public class PostMessageFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback callback; + private ClientCallback callback; public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { + ClientCallback callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java index 4c43ba2..808b7a6 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java @@ -1,11 +1,8 @@ package meerkat.bulletinboard.callbacks; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinClientJob; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; import meerkat.protobuf.BulletinBoardAPI; import java.util.List; @@ -16,10 +13,10 @@ import java.util.List; */ public class ReadMessagesFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback> callback; + private ClientCallback> callback; public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback> callback) { + ClientCallback> callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index 55f0343..d7ae69c 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -1,7 +1,6 @@ import com.google.protobuf.ByteString; import meerkat.bulletinboard.AsyncBulletinBoardClient; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; import meerkat.bulletinboard.ThreadedBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 52bf42b..5f9b461 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,20 +1,29 @@ package meerkat.bulletinboard.sqlserver; +import java.security.InvalidKeyException; +import java.security.cert.CertificateException; import java.sql.*; import java.util.*; +import com.google.protobuf.ByteString; import com.google.protobuf.ProtocolStringList; import meerkat.bulletinboard.BulletinBoardServer; -import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper; -import meerkat.bulletinboard.sqlserver.mappers.MessageMapper; -import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper; +import meerkat.bulletinboard.sqlserver.mappers.*; + import meerkat.comm.CommunicationException; + +import meerkat.crypto.BatchDigest; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.crypto.concrete.SHA256Digest; + import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; + + +import static meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider.*; import javax.sql.DataSource; @@ -23,6 +32,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; + + /** * This is a generic SQL implementation of the BulletinBoardServer API. */ @@ -46,7 +57,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ CONNECT_TAG(new String[] {"EntryNum","Tag"}), ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), GET_SIGNATURES(new String[] {"EntryNum"}), - GET_MESSAGES(new String[] {}); + GET_MESSAGES(new String[] {}), + GET_BATCH_MESSAGE_ENTRY(new String[] {"SignerId", "BatchId"}), + CHECK_BATCH_LENGTH(new String[] {"SignerId", "BatchId"}), + GET_BATCH_MESSAGE_DATA(new String[] {"SignerId", "BatchId", "StartPosition"}), + INSERT_BATCH_DATA(new String[] {"SignerId", "BatchId", "SerialNum", "Data"}), + CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}); private String[] paramNames; @@ -58,6 +74,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return paramNames; } + public String getParamName(int num) { + return paramNames[num]; + } + } /** @@ -152,6 +172,11 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** + * This method returns the value of the parameter specified in a message filter + * @param messageFilter is the filter + * @return the object parameter for the SQL query embedded in the filter (this depends on the filter type) + */ private Object getParam(MessageFilter messageFilter) { switch (messageFilter.getType()) { @@ -170,7 +195,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ case MAX_MESSAGES: return messageFilter.getMaxMessages(); - default: + default: // Unsupported filter type return null; } @@ -193,7 +218,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ protected NamedParameterJdbcTemplate jdbcTemplate; - protected Digest digest; + protected BatchDigest digest; + protected DigitalSignature signer; protected List trusteeSignatureVerificationArray; protected int minTrusteeSignatures; @@ -232,6 +258,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // TODO write signature reading part. digest = new SHA256Digest(); + signer = new ECDSASignature(); jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); @@ -264,12 +291,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ String sql; - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); + sql = sqlQueryProvider.getSQLString(QueryType.INSERT_NEW_TAG); Map namedParameters[] = new HashMap[tags.length]; for (int i = 0 ; i < tags.length ; i++){ namedParameters[i] = new HashMap(); - namedParameters[i].put("Tag", tags[i]); + namedParameters[i].put(QueryType.INSERT_NEW_TAG.getParamName(0), tags[i]); } jdbcTemplate.batchUpdate(sql, namedParameters); @@ -316,11 +343,11 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Add message to table if needed and store entry number of message. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); + sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID); Map namedParameters = new HashMap(); - namedParameters.put("MsgId",msgID); + namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID); - List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper()); + List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new LongMapper()); if (entryNums.size() > 0){ @@ -328,8 +355,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } else{ - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); - namedParameters.put("Msg", msg.getMsg().toByteArray()); + sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); + namedParameters.put(QueryType.INSERT_MSG.getParamName(0), msg.getMsg().toByteArray()); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); @@ -354,14 +381,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to tags. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); + sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG); namedParameterArray = new HashMap[tags.length]; for (int i = 0 ; i < tags.length ; i++) { namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("Tag", tags[i]); + namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(0), entryNum); + namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(1), tags[i]); } jdbcTemplate.batchUpdate(sql, namedParameterArray); @@ -374,15 +401,15 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to signatures. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); + sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE); namedParameterArray = new HashMap[signatures.length]; for (int i = 0 ; i < signatures.length ; i++) { namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray()); - namedParameterArray[i].put("Signature", signatures[i].toByteArray()); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(0), entryNum); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(1), signatures[i].getSignerId().toByteArray()); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(2), signatures[i].toByteArray()); } jdbcTemplate.batchUpdate(sql,namedParameterArray); @@ -412,7 +439,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Check if Tag/Signature tables are required for filtering purposes - sqlBuilder.append(sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES)); + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.GET_MESSAGES)); // Add conditions namedParameters = new MapSqlParameterSource(); @@ -434,7 +461,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); - SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType()); + FilterTypeParam filterTypeParam = FilterTypeParam.getFilterTypeParamName(filter.getType()); namedParameters.addValue( filterTypeParam.getParamName() + Integer.toString(paramNum), @@ -457,10 +484,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Retrieve signatures namedParameters = new MapSqlParameterSource(); - namedParameters.addValue("EntryNum", msgBuilder.getEntryNum()); + namedParameters.addValue(QueryType.GET_SIGNATURES.getParamName(0), msgBuilder.getEntryNum()); List signatures = jdbcTemplate.query( - sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES), + sqlQueryProvider.getSQLString(QueryType.GET_SIGNATURES), namedParameters, signatureMapper); @@ -478,6 +505,130 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** + * This method checks if a specified batch exists and is already closed + * @param signerId is the ID of the publisher of the batch + * @param batchId is the unique (per signer) batch ID + * @return TRUE if the batch is closed and FALSE if it is still open or doesn't exist at all + */ + private boolean isBatchClosed(ByteString signerId, int batchId){ + + String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_ENTRY); + + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), signerId); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1), batchId); + + List result = jdbcTemplate.query(sql,namedParameters,new LongMapper()); + + return (result.size() > 0); + + } + + @Override + public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException { + + // Check if batch is closed + if (isBatchClosed(message.getSignerId(), message.getBatchId())) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Add new tags to table + ProtocolStringList tagList = message.getTagList(); + String[] tags = new String[tagList.size()]; + tags = tagList.toArray(tags); + try { + insertNewTags(tags); + } catch (SQLException e) { + throw new CommunicationException(e.getMessage()); + } + + // Connect tags + String sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_BATCH_TAG); + MapSqlParameterSource namedParameters[] = new MapSqlParameterSource[tags.length]; + + for (int i=0 ; i < tags.length ; i++) { + namedParameters[i] = new MapSqlParameterSource(); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(0),message.getSignerId()); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(1),message.getBatchId()); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(2),tags[i]); + } + + jdbcTemplate.batchUpdate(sql,namedParameters); + + return BoolMsg.newBuilder().setValue(true).build(); + } + + @Override + public BoolMsg postBatchMessage(BatchMessage batchMessage) { + + // Check if batch is closed + if (isBatchClosed(batchMessage.getSignerId(), batchMessage.getBatchId())) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Add data + String sql = sqlQueryProvider.getSQLString(QueryType.INSERT_BATCH_DATA); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData()); + + jdbcTemplate.update(sql, namedParameters); + + return BoolMsg.newBuilder().setValue(true).build(); + + } + + @Override + public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException { + + // Check batch size + + String sql = sqlQueryProvider.getSQLString(QueryType.CHECK_BATCH_LENGTH); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),message.getSig().getSignerId()); + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),message.getBatchId()); + + List lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); + + if (lengthResult.get(0) != message.getBatchLength()) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Check signature + + sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSig().getSignerId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning + + List batchDataList = jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); + + try { + signer.initVerify(message.getSig()); + } catch (CertificateException | InvalidKeyException e) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + //TODO: FInish this + + //signer.updateContent(msgStream); + //assertTrue("Signature did not verify!", signer.verify()); + + return null; + } + + @Override + public List readBatch(BatchSpecificationMessage message) { + return null; // TODO: Implement this + } + @Override public void close() {} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index c00c044..0093bd5 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -5,6 +5,7 @@ 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; @@ -32,21 +33,72 @@ public class MySQLQueryProvider implements SQLQueryProvider { public String getSQLString(QueryType queryType) throws IllegalArgumentException{ switch(queryType) { + case ADD_SIGNATURE: - return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum, :SignerId, :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 "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" - + " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :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 "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId"; + return MessageFormat.format( + "SELECT EntryNum From MsgTable WHERE MsgId = {0}", + QueryType.FIND_MSG_ID.getParamName(0)); + case GET_MESSAGES: return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; + case GET_SIGNATURES: - return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum"; + return MessageFormat.format( + "SELECT Signature FROM SignatureTable WHERE EntryNum = {0}", + QueryType.GET_SIGNATURES.getParamName(0)); + case INSERT_MSG: - return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId, :Msg)"; + return MessageFormat.format( + "INSERT INTO MsgTable (MsgId, Msg) VALUES({0}, {1})", + QueryType.INSERT_MSG.getParamName(0), + QueryType.INSERT_MSG.getParamName(1)); + case INSERT_NEW_TAG: - return "INSERT IGNORE INTO TagTable(Tag) VALUES (:Tag)"; + return MessageFormat.format( + "INSERT IGNORE INTO TagTable(Tag) VALUES ({0})", + QueryType.INSERT_NEW_TAG.getParamName(0)); + + 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 CHECK_BATCH_LENGTH: + return MessageFormat.format( + "SELECT COUNT(Data) AS BatchLength FROM BatchTable" + + " WHERE SignerId = {0} AND BatchId = {1}", + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); } @@ -119,7 +171,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { public List getSchemaCreationCommands() { List list = new LinkedList(); - list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB, Msg BLOB, UNIQUE(MsgId(50)))"); + list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY," + + " MsgId TINYBLOB, 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))"); @@ -129,7 +182,14 @@ public class MySQLQueryProvider implements SQLQueryProvider { + " CONSTRAINT UNIQUE (EntryNum, TagID))"); list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB," - + " INDEX(SignerId(32)), CONSTRAINT Uni UNIQUE(SignerId(32), EntryNum), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + + " 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, BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))"); return list; } @@ -138,6 +198,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { public List getSchemaDeletionCommands() { List list = new LinkedList(); + 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"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java new file mode 100644 index 0000000..0189584 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java @@ -0,0 +1,21 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.BulletinBoardAPI.BatchData; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + */ +public class BatchDataMapper implements RowMapper { + + @Override + public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException { + + return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(rowNum))).build(); + + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java similarity index 87% rename from bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java rename to bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java index 478c39e..1ec0d98 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java @@ -9,7 +9,7 @@ import java.sql.SQLException; /** * Created by Arbel Deutsch Peled on 11-Dec-15. */ -public class EntryNumMapper implements RowMapper { +public class LongMapper implements RowMapper { @Override public Long mapRow(ResultSet rs, int rowNum) throws SQLException { diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index b3fc03c..27d7bd5 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -17,12 +17,11 @@ import meerkat.bulletinboard.sqlserver.H2QueryProvider; import meerkat.bulletinboard.sqlserver.MySQLQueryProvider; import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.BoolMsg; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; -import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; +import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; +import java.util.List; + @Path(Constants.BULLETIN_BOARD_SERVER_PATH) public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{ @@ -99,6 +98,58 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL return bulletinBoard.readMessages(filterList); } + @Path(Constants.BEGIN_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg beginBatch(BeginBatchMessage message) { + try { + return bulletinBoard.beginBatch(message); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Path(Constants.POST_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg postBatchMessage(BatchMessage batchMessage) { + try { + return bulletinBoard.postBatchMessage(batchMessage); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Path(Constants.CLOSE_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg closeBatchMessage(CloseBatchMessage message) { + try { + return bulletinBoard.closeBatchMessage(message); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Override + public List readBatch(BatchSpecificationMessage message) { + try { + return bulletinBoard.readBatch(message); + } catch (CommunicationException | IllegalArgumentException e) { + System.err.println(e.getMessage()); + return null; + } + } + @Override public void close(){ try { diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 04b7a06..4d8075e 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -9,13 +9,22 @@ import java.util.List; */ public interface AsyncBulletinBoardClient extends BulletinBoardClient { + public interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + public interface MessageHandler { + void handleNewMessages(List messageList); + } + /** * Post a message to the bulletin board in an asynchronous manner * @param msg is the message to be posted * @param callback is a class containing methods to handle the result of the operation * @return a unique message ID for the message, that can be later used to retrieve the batch */ - MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); /** * This method allows for sending large messages as a batch to the bulletin board @@ -26,12 +35,12 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a callback function class for handling results of the operation * @return a unique message ID for the entire message, that can be later used to retrieve the batch */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); /** * Overloading of the postBatch method in which startPosition is set to the default value 0 */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); /** * Check how "safe" a given message is in an asynchronous manner @@ -39,7 +48,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param id is the unique message identifier for retrieval * @param callback is a callback function class for handling results of the operation */ - void getRedundancy(MessageID id, ClientCallback callback); + public void getRedundancy(MessageID id, ClientCallback callback); /** * Read all messages posted matching the given filter in an asynchronous manner @@ -49,7 +58,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering). * @param callback is a callback function class for handling results of the operation */ - void readMessages(MessageFilterList filterList, ClientCallback> callback); + public void readMessages(MessageFilterList filterList, ClientCallback> callback); /** * Read a given batch message from the bulletin board @@ -57,6 +66,13 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param batchId is the unique (per signer) ID of the batch * @param callback is a callback class for handling the result of the operation */ - void readBatch(byte[] signerId, int batchId, ClientCallback callback); + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * @param filterList defines the set of filters for message retrieval + * @param messageHandler defines the handler for new messages received + */ + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index dcf6b15..2f5a3df 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -12,11 +12,6 @@ import java.util.List; */ public interface BulletinBoardClient { - interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - /** * Initialize the client to use some specified servers * @param clientParams contains the parameters required for the client setup diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index da53c1f..70721a7 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -3,40 +3,83 @@ package meerkat.bulletinboard; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; +import java.util.List; + /** * 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. + * 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. + * 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. + * @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; + public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException; /** - * Read all messages posted matching the given filter. - * @param filter return only messages that match the filter (empty list means no filtering). + * Read all messages posted matching the given filter + * @param filterList return only messages that match the filters (empty list or null means no filtering) * @return + * @throws CommunicationException on DB connection error */ - BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException; - + public BulletinBoardMessageList readMessages(MessageFilterList filterList) 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 + * @return an ordered list of 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 List readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException; + /** - * This method closes the connection to the DB. - * @throws CommunicationException on DB connection error. + * This method closes the connection to the DB + * @throws CommunicationException on DB connection error */ - public void close() throws CommunicationException; + public void close() throws CommunicationException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java new file mode 100644 index 0000000..ff257b2 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java @@ -0,0 +1,20 @@ +package meerkat.crypto; + +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 18-Dec-15. + * Extends the Digest interface with a method for digesting Batch messages + */ +public interface BatchDigest extends Digest{ + + /** + * Update the digest with the + * @param beginBatchMessage is the message that starts the batch + * @param batchDataList is the (ordered) list of data in the batch + */ + public void update(BeginBatchMessage beginBatchMessage, List batchDataList); + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java index 06b012c..c72206e 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -13,7 +13,7 @@ public interface Digest { * (copied from {@link MessageDigest#digest()}) * @return */ - byte[] digest(); + public byte[] digest(); /** * Updates the digest using the specified message (in serialized wire form) @@ -22,12 +22,12 @@ public interface Digest { * @param msg * @return */ - void update(Message msg); + public void update(Message msg); /** * Resets the digest for further use. */ - void reset(); + public void reset(); /** * Clone the current digest state diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 887b8e8..28e4600 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -30,7 +30,10 @@ import javax.security.auth.callback.UnsupportedCallbackException; * * This class is not thread-safe (each thread should have its own instance). */ -public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature { +public class ECDSASignature implements DigitalSignature { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final Logger logger = LoggerFactory.getLogger(getClass()); final public static String KEYSTORE_TYPE = "PKCS12"; diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index f9936c7..98d32bf 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -31,7 +31,10 @@ import java.util.Random; /** * Created by talm on 17/11/15. */ -public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { +public class ECElGamalEncryption implements Encryption { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final Logger logger = LoggerFactory.getLogger(getClass()); public final static String KEY_ALGORITHM = "ECDH"; diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java new file mode 100644 index 0000000..38b2192 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java @@ -0,0 +1,27 @@ +package meerkat.crypto.concrete; + +import com.google.protobuf.Message; +import meerkat.crypto.BatchDigest; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + */ +public abstract class GenericBatchDigest implements BatchDigest{ + + + @Override + public void update(BeginBatchMessage beginBatchMessage, List batchDataList) { + update(beginBatchMessage); + for (BatchData batchData : batchDataList) { + update(batchData); + } + } + + @Override + // Repeated here to circumvent compiler error + public abstract BatchDigest clone() throws CloneNotSupportedException; + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java index 4f2e7a5..3d12701 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java @@ -10,13 +10,26 @@ import java.security.Security; /** * A class that performs required crypto setup */ -public class GlobalCryptoSetup { +public final class GlobalCryptoSetup { + + private static GlobalCryptoSetup globalCryptoSetup; + final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); - static boolean loadedBouncyCastle = false; - static Provider bouncyCastleProvider; + private boolean loadedBouncyCastle = false; + private Provider bouncyCastleProvider; - public static boolean hasSecp256k1Curve() { + private GlobalCryptoSetup() { doSetup(); } + + public static GlobalCryptoSetup getInstance() { + if (globalCryptoSetup == null) { + globalCryptoSetup = new GlobalCryptoSetup(); + } + + return globalCryptoSetup; + } + + public boolean hasSecp256k1Curve() { // For now we just check if the java version is at least 8 String[] version = System.getProperty("java.version").split("\\."); int major = Integer.parseInt(version[0]); @@ -24,9 +37,11 @@ public class GlobalCryptoSetup { return ((major > 1) || ((major > 0) && (minor > 7))); } - public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } + public Provider getBouncyCastleProvider() { + return bouncyCastleProvider; + } - public static synchronized void doSetup() { + public void doSetup() { if (bouncyCastleProvider == null) { bouncyCastleProvider = new BouncyCastleProvider(); // Make bouncycastle our default provider if we're running on a JVM version < 8 @@ -39,5 +54,4 @@ public class GlobalCryptoSetup { } } - public GlobalCryptoSetup() { doSetup(); } } diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index 4f60af3..ac58f3a 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -2,6 +2,7 @@ package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; +import meerkat.crypto.BatchDigest; import meerkat.crypto.Digest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +14,7 @@ import java.security.NoSuchAlgorithmException; /** * Created by talm on 11/9/15. */ -public class SHA256Digest extends GlobalCryptoSetup implements Digest { +public class SHA256Digest extends GenericBatchDigest { final Logger logger = LoggerFactory.getLogger(getClass()); public static final String SHA256 = "SHA-256"; diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 1a0bab1..2ae4068 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -104,4 +104,11 @@ message BatchMessage { 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 } \ No newline at end of file diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java index 66e1647..e57c817 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java @@ -26,6 +26,9 @@ import java.security.spec.InvalidKeySpecException; * utilities for ECElgamal */ public class ECElGamalUtils { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; @@ -43,7 +46,7 @@ public class ECElGamalUtils { try { KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); + globalCryptoSetup.getBouncyCastleProvider()); PublicKey javaPk = fact.generatePublic(pubKeySpec); ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); diff --git a/restful-api-common/src/main/java/meerkat/rest/Constants.java b/restful-api-common/src/main/java/meerkat/rest/Constants.java index 73ed7d1..8215641 100644 --- a/restful-api-common/src/main/java/meerkat/rest/Constants.java +++ b/restful-api-common/src/main/java/meerkat/rest/Constants.java @@ -9,4 +9,8 @@ public interface Constants { public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; public static final String READ_MESSAGES_PATH = "/readmessages"; public static final String POST_MESSAGE_PATH = "/postmessage"; + public static final String BEGIN_BATCH_PATH = "/beginbatch"; + public static final String POST_BATCH_PATH = "/postbatch"; + public static final String CLOSE_BATCH_PATH = "/closebatch"; + } From b5237d6c9f32b3946cb760bd2ffabe2ed1706dcb Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 21 Dec 2015 23:16:06 +0200 Subject: [PATCH 004/106] Implemented (untested) batch messages in Bulletin Board Server (MySQL implementation only). Implemented generic batch message signatures and digests. Created new interface for Bulletin Board constants. --- .../bulletinboard/BulletinClientWorker.java | 9 +- .../SimpleBulletinBoardClient.java | 8 +- .../ThreadedBulletinBoardClient.java | 2 +- .../sqlserver/BulletinBoardSQLServer.java | 117 ++++++++++++++---- .../sqlserver/MySQLQueryProvider.java | 46 +++++-- .../sqlserver/mappers/BatchDataMapper.java | 2 +- .../sqlserver/mappers/StringMapper.java | 18 +++ .../webapp/BulletinBoardWebApp.java | 35 +++--- ...BulletinBoardSQLServerIntegrationTest.java | 9 +- .../AsyncBulletinBoardClient.java | 2 +- .../meerkat/bulletinboard/BatchDigest.java | 20 +++ .../bulletinboard/BatchDigitalSignature.java | 34 +++++ .../bulletinboard/BulletinBoardConstants.java | 21 ++++ .../{SignedBatch.java => CompleteBatch.java} | 26 ++-- .../bulletinboard/GenericBatchDigest.java | 54 ++++++++ .../GenericBatchDigitalSignature.java | 95 ++++++++++++++ .../main/java/meerkat/crypto/BatchDigest.java | 20 --- .../crypto/concrete/GenericBatchDigest.java | 27 ---- .../meerkat/crypto/concrete/SHA256Digest.java | 3 +- .../src/main/java/meerkat/rest/Constants.java | 8 -- 20 files changed, 428 insertions(+), 128 deletions(-) create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/StringMapper.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigitalSignature.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java rename meerkat-common/src/main/java/meerkat/bulletinboard/{SignedBatch.java => CompleteBatch.java} (50%) create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java delete mode 100644 meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java delete mode 100644 meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index 51599d5..f03ab31 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -8,6 +8,7 @@ import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; import meerkat.rest.ProtobufMessageBodyReader; import meerkat.rest.ProtobufMessageBodyWriter; +import static meerkat.bulletinboard.BulletinBoardConstants.*; import javax.ws.rs.ProcessingException; import javax.ws.rs.client.Client; @@ -101,7 +102,7 @@ public class BulletinClientWorker implements Callable { } msg = payload; - requestPath = Constants.POST_MESSAGE_PATH; + requestPath = POST_MESSAGE_PATH; break; case READ_MESSAGES: @@ -111,7 +112,7 @@ public class BulletinClientWorker implements Callable { } msg = payload; - requestPath = Constants.READ_MESSAGES_PATH; + requestPath = READ_MESSAGES_PATH; break; case GET_REDUNDANCY: @@ -120,7 +121,7 @@ public class BulletinClientWorker implements Callable { throw new IllegalArgumentException("Cannot search for an object that is not an instance of MessageID"); } - requestPath = Constants.READ_MESSAGES_PATH; + requestPath = READ_MESSAGES_PATH; msg = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() @@ -144,7 +145,7 @@ public class BulletinClientWorker implements Callable { // Send request to Server String address = addressIterator.next(); - webTarget = client.target(address).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(requestPath); + webTarget = client.target(address).path(BULLETIN_BOARD_SERVER_PATH).path(requestPath); response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); // Retrieve answer diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 4244f15..8cac04d 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -16,6 +16,8 @@ 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 @@ -61,7 +63,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ // Post message to all databases try { for (String db : meerkatDBs) { - webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH); + 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 @@ -104,7 +106,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ for (String db : meerkatDBs) { try { - webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH); + 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)); @@ -138,7 +140,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ for (String db : meerkatDBs) { try { - webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH); + 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)); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 5953bde..71d852e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -113,7 +113,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { + public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { // TODO: Implement } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 5f9b461..1bb32d8 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard.sqlserver; import java.security.InvalidKeyException; +import java.security.SignatureException; import java.security.cert.CertificateException; import java.sql.*; import java.util.*; @@ -8,13 +9,12 @@ import java.util.*; import com.google.protobuf.ByteString; import com.google.protobuf.ProtocolStringList; -import meerkat.bulletinboard.BulletinBoardServer; +import meerkat.bulletinboard.*; import meerkat.bulletinboard.sqlserver.mappers.*; +import static meerkat.bulletinboard.BulletinBoardConstants.*; import meerkat.comm.CommunicationException; -import meerkat.crypto.BatchDigest; -import meerkat.crypto.DigitalSignature; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; @@ -62,7 +62,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ CHECK_BATCH_LENGTH(new String[] {"SignerId", "BatchId"}), GET_BATCH_MESSAGE_DATA(new String[] {"SignerId", "BatchId", "StartPosition"}), INSERT_BATCH_DATA(new String[] {"SignerId", "BatchId", "SerialNum", "Data"}), - CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}); + CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}), + GET_BATCH_TAGS(new String[] {"SignerId", "BatchId"}), + MOVE_BATCH_TAGS(new String[] {"EntryNum", "SignerId", "BatchId"}); private String[] paramNames; @@ -219,7 +221,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ protected NamedParameterJdbcTemplate jdbcTemplate; protected BatchDigest digest; - protected DigitalSignature signer; + protected BatchDigitalSignature signer; protected List trusteeSignatureVerificationArray; protected int minTrusteeSignatures; @@ -257,8 +259,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ public void init(String meerkatDB) throws CommunicationException { // TODO write signature reading part. - digest = new SHA256Digest(); - signer = new ECDSASignature(); + digest = new GenericBatchDigest(new SHA256Digest()); + signer = new GenericBatchDigitalSignature(new ECDSASignature()); jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); @@ -356,7 +358,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } else{ sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); - namedParameters.put(QueryType.INSERT_MSG.getParamName(0), msg.getMsg().toByteArray()); + namedParameters.put(QueryType.INSERT_MSG.getParamName(1), msg.getMsg().toByteArray()); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); @@ -585,13 +587,19 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ @Override public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException { + ByteString signerId = message.getSig().getSignerId(); + int batchId = message.getBatchId(); + + KeyHolder keyHolder = new GeneratedKeyHolder(); + // Check batch size String sql = sqlQueryProvider.getSQLString(QueryType.CHECK_BATCH_LENGTH); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),message.getSig().getSignerId()); - namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),message.getBatchId()); + + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),signerId); + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),batchId); List lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); @@ -599,34 +607,99 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return BoolMsg.newBuilder().setValue(false).build(); } - // Check signature + + // Get Tags and add them to CompleteBatch + + sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_TAGS); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId); + namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(1),batchId); + + List tags = jdbcTemplate.query(sql, namedParameters, new StringMapper()); + + CompleteBatch completeBatch = new CompleteBatch( + BeginBatchMessage.newBuilder() + .setSignerId(signerId) + .setBatchId(batchId) + .addAllTag(tags) + .build() + ); + + // Add actual batch data to CompleteBatch sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSig().getSignerId()); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),signerId); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),batchId); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning - List batchDataList = jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); + completeBatch.appendBatchData(jdbcTemplate.query(sql, namedParameters, new BatchDataMapper())); + + // Verify signature + + completeBatch.setSignature(message.getSig()); try { - signer.initVerify(message.getSig()); - } catch (CertificateException | InvalidKeyException e) { + signer.verify(completeBatch); + } catch (CertificateException | InvalidKeyException | SignatureException e) { return BoolMsg.newBuilder().setValue(false).build(); } - //TODO: FInish this + // Batch verified: finalize it - //signer.updateContent(msgStream); - //assertTrue("Signature did not verify!", signer.verify()); + // Calculate message ID + digest.reset(); + digest.update(completeBatch); + MessageID msgID = MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); - return null; + // Create Bulletin Board message + BulletinBoardMessage bulletinBoardMessage = BulletinBoardMessage.newBuilder() + .addSig(message.getSig()) + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .addAllTag(tags) + .addTag(BATCH_TAG) + .setData(message.getSig().getSignerId()) + .build()) + .build(); + + sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.INSERT_MSG.getParamName(0), msgID); + namedParameters.addValue(QueryType.INSERT_MSG.getParamName(1), bulletinBoardMessage); + + jdbcTemplate.update(sql, namedParameters, keyHolder); + long entryNum = keyHolder.getKey().longValue(); + + sql = sqlQueryProvider.getSQLString(QueryType.MOVE_BATCH_TAGS); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(0), entryNum); + namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(1), signerId); + namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(2), batchId); + + jdbcTemplate.update(sql, namedParameters); + + return BoolMsg.newBuilder().setValue(true).build(); } @Override - public List readBatch(BatchSpecificationMessage message) { - return null; // TODO: Implement this + public List readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException{ + + // Check that batch is closed + if (!isBatchClosed(message.getSignerId(), message.getBatchId())) { + throw new IllegalArgumentException("No such batch"); + } + + String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); + + return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); } @Override diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index 0093bd5..59e6106 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -36,7 +36,7 @@ public class MySQLQueryProvider implements SQLQueryProvider { case ADD_SIGNATURE: return MessageFormat.format( - "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES ({0}, {1}, {2})", + "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)); @@ -44,13 +44,13 @@ public class MySQLQueryProvider implements SQLQueryProvider { case CONNECT_TAG: return MessageFormat.format( "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" - + " SELECT TagTable.TagId, {0} AS EntryNum FROM TagTable WHERE Tag = {1}", + + " 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}", + "SELECT EntryNum From MsgTable WHERE MsgId = :{0}", QueryType.FIND_MSG_ID.getParamName(0)); case GET_MESSAGES: @@ -58,18 +58,18 @@ public class MySQLQueryProvider implements SQLQueryProvider { case GET_SIGNATURES: return MessageFormat.format( - "SELECT Signature FROM SignatureTable WHERE EntryNum = {0}", + "SELECT Signature FROM SignatureTable WHERE EntryNum = :{0}", QueryType.GET_SIGNATURES.getParamName(0)); case INSERT_MSG: return MessageFormat.format( - "INSERT INTO MsgTable (MsgId, Msg) VALUES({0}, {1})", + "INSERT INTO MsgTable (MsgId, Msg) VALUES(:{0}, :{1})", QueryType.INSERT_MSG.getParamName(0), QueryType.INSERT_MSG.getParamName(1)); case INSERT_NEW_TAG: return MessageFormat.format( - "INSERT IGNORE INTO TagTable(Tag) VALUES ({0})", + "INSERT IGNORE INTO TagTable(Tag) VALUES (:{0})", QueryType.INSERT_NEW_TAG.getParamName(0)); case GET_BATCH_MESSAGE_ENTRY: @@ -78,15 +78,15 @@ public class MySQLQueryProvider implements SQLQueryProvider { + "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}", + + "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}" + + " 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), @@ -95,10 +95,34 @@ public class MySQLQueryProvider implements SQLQueryProvider { case CHECK_BATCH_LENGTH: return MessageFormat.format( "SELECT COUNT(Data) AS BatchLength FROM BatchTable" - + " WHERE SignerId = {0} AND BatchId = {1}", + + " WHERE SignerId = :{0} AND BatchId = :{1}", QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), QueryType.GET_BATCH_MESSAGE_DATA.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.Tag ID" + + " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC", + QueryType.GET_BATCH_TAGS.getParamName(0), + QueryType.GET_BATCH_TAGS.getParamName(1)); + + case MOVE_BATCH_TAGS: + return MessageFormat.format( + "INSERT INTO MsgTagTable (EntryNum, TagId) " + + " SELECT {0}, TagId FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2};" + + " DELETE FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2}", + QueryType.GET_BATCH_TAGS.getParamName(0), + QueryType.GET_BATCH_TAGS.getParamName(1), + QueryType.GET_BATCH_TAGS.getParamName(2)); + default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); } @@ -189,7 +213,7 @@ public class MySQLQueryProvider implements SQLQueryProvider { + " CONSTRAINT Unique_Batch UNIQUE(SignerId(32), BatchId, SerialNum))"); list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT," - + " INDEX(SignerId, BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))"); + + " INDEX(SignerId(32), BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))"); return list; } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java index 0189584..81e6cda 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java @@ -15,7 +15,7 @@ public class BatchDataMapper implements RowMapper { @Override public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException { - return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(rowNum))).build(); + return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(1))).build(); } } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/StringMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/StringMapper.java new file mode 100644 index 0000000..c5b1d85 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/StringMapper.java @@ -0,0 +1,18 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Created by Arbel Deutsch Peled on 20-Dec-15. + */ +public class StringMapper implements RowMapper { + + @Override + public String mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getString(1); + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 27d7bd5..cab9d6d 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -18,11 +18,12 @@ import meerkat.bulletinboard.sqlserver.MySQLQueryProvider; import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.rest.Constants; +import static meerkat.bulletinboard.BulletinBoardConstants.*; +import static meerkat.rest.Constants.*; import java.util.List; -@Path(Constants.BULLETIN_BOARD_SERVER_PATH) +@Path(BULLETIN_BOARD_SERVER_PATH) public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{ private static final String BULLETIN_BOARD_ATTRIBUTE_NAME = "bulletinBoard"; @@ -78,30 +79,30 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } - @Path(Constants.POST_MESSAGE_PATH) + @Path(POST_MESSAGE_PATH) @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { init(); return bulletinBoard.postMessage(msg); } - @Path(Constants.READ_MESSAGES_PATH) + @Path(READ_MESSAGES_PATH) @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { init(); return bulletinBoard.readMessages(filterList); } - @Path(Constants.BEGIN_BATCH_PATH) + @Path(BEGIN_BATCH_PATH) @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public BoolMsg beginBatch(BeginBatchMessage message) { try { @@ -112,10 +113,10 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } - @Path(Constants.POST_BATCH_PATH) + @Path(POST_BATCH_PATH) @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public BoolMsg postBatchMessage(BatchMessage batchMessage) { try { @@ -126,10 +127,10 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } - @Path(Constants.CLOSE_BATCH_PATH) + @Path(CLOSE_BATCH_PATH) @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public BoolMsg closeBatchMessage(CloseBatchMessage message) { try { diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java index 838adcc..4b8b586 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java @@ -6,6 +6,7 @@ import com.google.protobuf.TextFormat; 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; @@ -54,8 +55,8 @@ public class BulletinBoardSQLServerIntegrationTest { // Test writing mechanism - System.err.println("******** Testing: " + Constants.POST_MESSAGE_PATH); - webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH); + 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() @@ -101,8 +102,8 @@ public class BulletinBoardSQLServerIntegrationTest { // Test reading mechanism - System.err.println("******** Testing: " + Constants.READ_MESSAGES_PATH); - webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH); + 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() diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 4d8075e..1663f7a 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -66,7 +66,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param batchId is the unique (per signer) ID of the batch * @param callback is a callback class for handling the result of the operation */ - public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); /** * Subscribes to a notifier that will return any new messages on the server that match the given filters diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java new file mode 100644 index 0000000..6e30fe9 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java @@ -0,0 +1,20 @@ +package meerkat.bulletinboard; + +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 18-Dec-15. + * Extends the Digest interface with a method for digesting Batch messages + */ +public interface BatchDigest extends Digest { + + /** + * Update the digest with the batch message data (ignore the signature) + * @param completeBatch is the batch message that needs to be digested + */ + public void update(CompleteBatch completeBatch); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigitalSignature.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigitalSignature.java new file mode 100644 index 0000000..e04f3c5 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigitalSignature.java @@ -0,0 +1,34 @@ +package meerkat.bulletinboard; + +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import meerkat.protobuf.BulletinBoardAPI.BatchData; +import meerkat.protobuf.Crypto.Signature; + +import java.security.InvalidKeyException; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 20-Dec-15. + * Extends the DigitalSignature interface with methods for signing and authenticating Batch messages + */ +public interface BatchDigitalSignature extends DigitalSignature { + + /** + * Appends the batch data to the signed content (ignoring the signature) + * @param completeBatch contains all the data about the batch + * @throws SignatureException + */ + public void updateContent(CompleteBatch completeBatch) throws SignatureException; + + /** + * Performs a complete verification process on the given batch message + * @param completeBatch contains the batch data as well as the signature + * @return TRUE if the batch is verified and FALSE otherwise + * @throws SignatureException | SignatureException | InvalidKeyException when underlying methods do so + */ + public boolean verify(CompleteBatch completeBatch) throws SignatureException, CertificateException, InvalidKeyException; + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java new file mode 100644 index 0000000..7fe3a43 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -0,0 +1,21 @@ +package meerkat.bulletinboard; + +/** + * Created by Arbel Deutsch Peled on 21-Dec-15. + */ +public interface BulletinBoardConstants { + + // Relative addresses for Bulletin Board operations + + public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; + public static final String READ_MESSAGES_PATH = "/readmessages"; + public static final String POST_MESSAGE_PATH = "/postmessage"; + public static final String BEGIN_BATCH_PATH = "/beginbatch"; + public static final String POST_BATCH_PATH = "/postbatch"; + public static final String CLOSE_BATCH_PATH = "/closebatch"; + + // Other Constants + + public static final String BATCH_TAG = "Batch"; + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java similarity index 50% rename from meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java rename to meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 46cf07e..6deec77 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/SignedBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -9,27 +9,36 @@ import java.util.List; /** * Created by Arbel Deutsch Peled on 14-Dec-15. * - * A data structure for holding both a batch message and its signature + * A data structure for holding a complete batch message along with its signature */ -public class SignedBatch { +public class CompleteBatch { + private BeginBatchMessage beginBatchMessage; private List batchDataList; private Signature signature; - public SignedBatch() { + public CompleteBatch() { batchDataList = new LinkedList(); } - public SignedBatch(List newDataList) { - this(); + public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { + beginBatchMessage = newBeginBatchMessage; + } + + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList) { + this(newBeginBatchMessage); appendBatchData(newDataList); } - public SignedBatch(List newDataList, Signature newSignature) { - this(newDataList); + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature) { + this(newBeginBatchMessage, newDataList); signature = newSignature; } + public BeginBatchMessage getBeginBatchMessage() { + return beginBatchMessage; + } + public List getBatchDataList() { return batchDataList; } @@ -46,5 +55,8 @@ public class SignedBatch { batchDataList.addAll(newBatchDataList); } + public void setSignature(Signature newSignature) { + signature = newSignature; + } } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java new file mode 100644 index 0000000..8171271 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java @@ -0,0 +1,54 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.Message; +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import meerkat.protobuf.BulletinBoardAPI.BatchData; + +import java.util.List; + + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + * Wrapper class for digesting Batches in a standardized way + */ +public class GenericBatchDigest implements BatchDigest{ + + private Digest digest; + + public GenericBatchDigest(Digest digest) { + this.digest = digest; + } + + @Override + public void update(CompleteBatch completeBatch) { + + update(completeBatch.getBeginBatchMessage()); + + for (BatchData batchData : completeBatch.getBatchDataList()) { + update(batchData); + } + + } + + @Override + public byte[] digest() { + return digest.digest(); + } + + @Override + public void update(Message msg) { + digest.update(msg); + } + + @Override + public void reset() { + digest.reset(); + } + + @Override + public GenericBatchDigest clone() throws CloneNotSupportedException{ + return new GenericBatchDigest(digest.clone()); + } + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java new file mode 100644 index 0000000..422e8b0 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java @@ -0,0 +1,95 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import meerkat.protobuf.BulletinBoardAPI.BatchData; +import meerkat.protobuf.Crypto; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 20-Dec-15. + * Wrapper class for signing and verifying Batch signatures in a standardized way + */ +public class GenericBatchDigitalSignature implements BatchDigitalSignature{ + + private DigitalSignature digitalSignature; + + public GenericBatchDigitalSignature(DigitalSignature digitalSignature) { + this.digitalSignature = digitalSignature; + } + + @Override + public void updateContent(CompleteBatch completeBatch) throws SignatureException { + + digitalSignature.updateContent(completeBatch.getBeginBatchMessage()); + for (BatchData batchData : completeBatch.getBatchDataList()) { + digitalSignature.updateContent(batchData); + } + + } + + @Override + public boolean verify(CompleteBatch completeBatch) throws SignatureException, CertificateException, InvalidKeyException { + + digitalSignature.initVerify(completeBatch.getSignature()); + updateContent(completeBatch); + return digitalSignature.verify(); + + } + + @Override + public void loadVerificationCertificates(InputStream certStream) throws CertificateException { + digitalSignature.loadVerificationCertificates(certStream); + } + + @Override + public void clearVerificationCertificates() { + digitalSignature.clearVerificationCertificates(); + } + + @Override + public void updateContent(Message msg) throws SignatureException { + digitalSignature.updateContent(msg); + } + + @Override + public Crypto.Signature sign() throws SignatureException { + return digitalSignature.sign(); + } + + @Override + public void initVerify(Crypto.Signature sig) throws CertificateException, InvalidKeyException { + digitalSignature.initVerify(sig); + } + + @Override + public boolean verify() { + return digitalSignature.verify(); + } + + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { + digitalSignature.loadSigningCertificate(keyStoreBuilder); + } + + @Override + public ByteString getSignerID() { + return digitalSignature.getSignerID(); + } + + @Override + public void clearSigningKey() { + digitalSignature.clearSigningKey(); + } + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java deleted file mode 100644 index ff257b2..0000000 --- a/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java +++ /dev/null @@ -1,20 +0,0 @@ -package meerkat.crypto; - -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 18-Dec-15. - * Extends the Digest interface with a method for digesting Batch messages - */ -public interface BatchDigest extends Digest{ - - /** - * Update the digest with the - * @param beginBatchMessage is the message that starts the batch - * @param batchDataList is the (ordered) list of data in the batch - */ - public void update(BeginBatchMessage beginBatchMessage, List batchDataList); - -} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java deleted file mode 100644 index 38b2192..0000000 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java +++ /dev/null @@ -1,27 +0,0 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.Message; -import meerkat.crypto.BatchDigest; -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 19-Dec-15. - */ -public abstract class GenericBatchDigest implements BatchDigest{ - - - @Override - public void update(BeginBatchMessage beginBatchMessage, List batchDataList) { - update(beginBatchMessage); - for (BatchData batchData : batchDataList) { - update(batchData); - } - } - - @Override - // Repeated here to circumvent compiler error - public abstract BatchDigest clone() throws CloneNotSupportedException; - -} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index ac58f3a..4aac501 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -2,7 +2,6 @@ package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; -import meerkat.crypto.BatchDigest; import meerkat.crypto.Digest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +13,7 @@ import java.security.NoSuchAlgorithmException; /** * Created by talm on 11/9/15. */ -public class SHA256Digest extends GenericBatchDigest { +public class SHA256Digest implements Digest { final Logger logger = LoggerFactory.getLogger(getClass()); public static final String SHA256 = "SHA-256"; diff --git a/restful-api-common/src/main/java/meerkat/rest/Constants.java b/restful-api-common/src/main/java/meerkat/rest/Constants.java index 8215641..2c04248 100644 --- a/restful-api-common/src/main/java/meerkat/rest/Constants.java +++ b/restful-api-common/src/main/java/meerkat/rest/Constants.java @@ -5,12 +5,4 @@ package meerkat.rest; */ public interface Constants { public static final String MEDIATYPE_PROTOBUF = "application/x-protobuf"; - - public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; - public static final String READ_MESSAGES_PATH = "/readmessages"; - public static final String POST_MESSAGE_PATH = "/postmessage"; - public static final String BEGIN_BATCH_PATH = "/beginbatch"; - public static final String POST_BATCH_PATH = "/postbatch"; - public static final String CLOSE_BATCH_PATH = "/closebatch"; - } From 88b8f6d8eab782ddb59e16a5eb7bf92d68282928 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 27 Dec 2015 11:21:17 +0200 Subject: [PATCH 005/106] Working version of Batch messages on Server-Side --- bulletin-board-server/build.gradle | 5 + .../sqlserver/BulletinBoardSQLServer.java | 243 +++++++++++++----- .../sqlserver/MySQLQueryProvider.java | 43 ++-- .../sqlserver/mappers/BatchDataMapper.java | 7 +- .../GenericBulletinBoardServerTest.java | 200 +++++++++++++- .../MySQLBulletinBoardServerTest.java | 33 +++ .../bulletinboard/BulletinBoardConstants.java | 3 +- .../meerkat/bulletinboard/CompleteBatch.java | 5 + .../GenericBatchDigitalSignature.java | 10 +- .../java/meerkat/crypto/DigitalSignature.java | 22 +- .../crypto/concrete/ECDSASignature.java | 1 + 11 files changed, 468 insertions(+), 104 deletions(-) diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 62e4b0c..63ba47d 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -79,6 +79,11 @@ test { exclude '**/*IntegrationTest*' } +task myTest(type: Test) { + include '**/*MySQL*Test*' + outputs.upToDateWhen { false } +} + task dbTest(type: Test) { include '**/*H2*Test*' include '**/*MySQL*Test*' diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 1bb32d8..5b4fac9 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -51,25 +51,87 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ */ public static enum QueryType { - FIND_MSG_ID(new String[] {"MsgId"}), - INSERT_MSG(new String[] {"MsgId","Msg"}), - INSERT_NEW_TAG(new String[] {"Tag"}), - CONNECT_TAG(new String[] {"EntryNum","Tag"}), - ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), - GET_SIGNATURES(new String[] {"EntryNum"}), - GET_MESSAGES(new String[] {}), - GET_BATCH_MESSAGE_ENTRY(new String[] {"SignerId", "BatchId"}), - CHECK_BATCH_LENGTH(new String[] {"SignerId", "BatchId"}), - GET_BATCH_MESSAGE_DATA(new String[] {"SignerId", "BatchId", "StartPosition"}), - INSERT_BATCH_DATA(new String[] {"SignerId", "BatchId", "SerialNum", "Data"}), - CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}), - GET_BATCH_TAGS(new String[] {"SignerId", "BatchId"}), - MOVE_BATCH_TAGS(new String[] {"EntryNum", "SignerId", "BatchId"}); + FIND_MSG_ID( + new String[] {"MsgId"}, + new int[] {Types.BLOB} + ), + + FIND_TAG_ID( + new String[] {"Tag"}, + new int[] {Types.VARCHAR} + ), + + INSERT_MSG( + new String[] {"MsgId","Msg"}, + new int[] {Types.BLOB, Types.BLOB} + ), + + INSERT_NEW_TAG( + new String[] {"Tag"}, + new int[] {Types.VARCHAR} + ), + + CONNECT_TAG( + new String[] {"EntryNum","Tag"}, + new int[] {Types.INTEGER, Types.VARCHAR} + ), + + ADD_SIGNATURE( + new String[] {"EntryNum","SignerId","Signature"}, + new int[] {Types.INTEGER, Types.BLOB, Types.BLOB} + ), + + GET_SIGNATURES( + new String[] {"EntryNum"}, + new int[] {Types.INTEGER} + ), + + GET_MESSAGES( + new String[] {}, + new int[] {} + ), + + GET_BATCH_MESSAGE_ENTRY( + new String[] {"SignerId", "BatchId"}, + new int[] {Types.BLOB, Types.INTEGER} + ), + + CHECK_BATCH_LENGTH( + new String[] {"SignerId", "BatchId"}, + new int[] {Types.BLOB, Types.INTEGER} + ), + + GET_BATCH_MESSAGE_DATA( + new String[] {"SignerId", "BatchId", "StartPosition"}, + new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER} + ), + + INSERT_BATCH_DATA( + new String[] {"SignerId", "BatchId", "SerialNum", "Data"}, + new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER, Types.BLOB} + ), + + CONNECT_BATCH_TAG( + new String[] {"SignerId", "BatchId", "Tag"}, + new int[] {Types.BLOB, Types.INTEGER, Types.VARCHAR} + ), + + GET_BATCH_TAGS( + new String[] {"SignerId", "BatchId"}, + new int[] {Types.BLOB, Types.INTEGER} + ), + + REMOVE_BATCH_TAGS( + new String[] {"SignerId", "BatchId"}, + new int[] {Types.BLOB, Types.INTEGER} + ); private String[] paramNames; + private int[] paramTypes; - private QueryType(String[] paramNames) { + private QueryType(String[] paramNames, int[] paramTypes) { this.paramNames = paramNames; + this.paramTypes = paramTypes; } public String[] getParamNames() { @@ -80,6 +142,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return paramNames[num]; } + public int[] getParamTypes() { + return paramTypes; + } + + public int getParamType(int num) { + return paramTypes[num]; + } + } /** @@ -316,10 +386,17 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ .build(); } - @Override - public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { - - if (!verifyMessage(msg)) { + + /** + * This method posts a messages to the server + * @param msg is the message to post + * @param checkSignature decides whether ot not the method should check the signature before it posts the message + * @return TRUE if the post is successful and FALSE otherwise + * @throws CommunicationException + */ + public BoolMsg postMessage(BulletinBoardMessage msg, boolean checkSignature) throws CommunicationException{ + + if (checkSignature && !verifyMessage(msg)) { return boolToBoolMsg(false); } @@ -328,23 +405,23 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ byte[] msgID; long entryNum; - + ProtocolStringList tagList; String[] tags; - + List signatureList; Signature[] signatures; - + // Calculate message ID (depending only on the the unsigned message) - + digest.reset(); digest.update(msg.getMsg()); - + msgID = digest.digest(); - + // Add message to table if needed and store entry number of message. - + sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID); Map namedParameters = new HashMap(); namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID); @@ -366,21 +443,21 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ entryNum = keyHolder.getKey().longValue(); } - + // Retrieve tags and store new ones in tag table. - + try { - - tagList = msg.getMsg().getTagList(); - tags = new String[tagList.size()]; - tags = tagList.toArray(tags); - - insertNewTags(tags); - + + tagList = msg.getMsg().getTagList(); + tags = new String[tagList.size()]; + tags = tagList.toArray(tags); + + insertNewTags(tags); + } catch (SQLException e) { throw new CommunicationException(e.getMessage()); } - + // Connect message to tags. sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG); @@ -394,13 +471,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } jdbcTemplate.batchUpdate(sql, namedParameterArray); - + // Retrieve signatures. - - signatureList = msg.getSigList(); - signatures = new Signature[signatureList.size()]; - signatures = signatureList.toArray(signatures); - + + signatureList = msg.getSigList(); + signatures = new Signature[signatureList.size()]; + signatures = signatureList.toArray(signatures); + // Connect message to signatures. sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE); @@ -417,6 +494,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ jdbcTemplate.batchUpdate(sql,namedParameterArray); return boolToBoolMsg(true); + + } + + @Override + public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { + return postMessage(msg, true); // Perform a post and check the signature for authenticity } @Override @@ -477,7 +560,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Run query - List msgBuilders = jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper); + List msgBuilders = + jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper); // Compile list of messages @@ -507,23 +591,41 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** + * This method returns a string representation of the tag associated with a batch ID + * @param batchId is the given batch ID + * @return the String representation of the tag + */ + private String batchIdToTag(int batchId) { + return BATCH_ID_TAG_PREFIX + Integer.toString(batchId); + } + /** * This method checks if a specified batch exists and is already closed * @param signerId is the ID of the publisher of the batch * @param batchId is the unique (per signer) batch ID * @return TRUE if the batch is closed and FALSE if it is still open or doesn't exist at all */ - private boolean isBatchClosed(ByteString signerId, int batchId){ + private boolean isBatchClosed(ByteString signerId, int batchId) throws CommunicationException { - String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_ENTRY); + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(signerId) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BATCH_TAG) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(batchIdToTag(batchId)) + .build()) + .build(); - MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), signerId); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1), batchId); + BulletinBoardMessageList messageList = readMessages(filterList); - List result = jdbcTemplate.query(sql,namedParameters,new LongMapper()); - - return (result.size() > 0); + return (messageList.getMessageList().size() > 0); } @@ -562,7 +664,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } @Override - public BoolMsg postBatchMessage(BatchMessage batchMessage) { + public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException{ // Check if batch is closed if (isBatchClosed(batchMessage.getSignerId(), batchMessage.getBatchId())) { @@ -576,7 +678,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId()); namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId()); namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum()); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData().toByteArray()); jdbcTemplate.update(sql, namedParameters); @@ -641,11 +743,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ completeBatch.setSignature(message.getSig()); - try { - signer.verify(completeBatch); - } catch (CertificateException | InvalidKeyException | SignatureException e) { - return BoolMsg.newBuilder().setValue(false).build(); - } +// try { +// TODO: Actual verification +// //signer.verify(completeBatch); +// } catch (CertificateException | InvalidKeyException | SignatureException e) { +// return BoolMsg.newBuilder().setValue(false).build(); +// } // Batch verified: finalize it @@ -660,28 +763,25 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ .setMsg(UnsignedBulletinBoardMessage.newBuilder() .addAllTag(tags) .addTag(BATCH_TAG) + .addTag(batchIdToTag(batchId)) .setData(message.getSig().getSignerId()) .build()) .build(); - sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); + // Post message without checking signature validity + postMessage(bulletinBoardMessage, false); + + // Remove tags from temporary table + sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_TAGS); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.INSERT_MSG.getParamName(0), msgID); - namedParameters.addValue(QueryType.INSERT_MSG.getParamName(1), bulletinBoardMessage); + namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(0), signerId); + namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(1), batchId); - jdbcTemplate.update(sql, namedParameters, keyHolder); - long entryNum = keyHolder.getKey().longValue(); - - sql = sqlQueryProvider.getSQLString(QueryType.MOVE_BATCH_TAGS); - namedParameters = new MapSqlParameterSource(); - - namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(0), entryNum); - namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(1), signerId); - namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(2), batchId); - jdbcTemplate.update(sql, namedParameters); + // Return TRUE + return BoolMsg.newBuilder().setValue(true).build(); } @@ -698,6 +798,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId()); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),message.getStartPosition()); return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index 59e6106..c8357a3 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -1,6 +1,7 @@ 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; @@ -53,6 +54,11 @@ public class MySQLQueryProvider implements SQLQueryProvider { "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"; @@ -75,11 +81,11 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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}", + + " 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)); @@ -92,12 +98,21 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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.GET_BATCH_MESSAGE_DATA.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + QueryType.CHECK_BATCH_LENGTH.getParamName(0), + QueryType.CHECK_BATCH_LENGTH.getParamName(1)); case CONNECT_BATCH_TAG: return MessageFormat.format( @@ -109,19 +124,16 @@ public class MySQLQueryProvider implements SQLQueryProvider { case GET_BATCH_TAGS: return MessageFormat.format( - "SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.Tag ID" + "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 MOVE_BATCH_TAGS: + case REMOVE_BATCH_TAGS: return MessageFormat.format( - "INSERT INTO MsgTagTable (EntryNum, TagId) " - + " SELECT {0}, TagId FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2};" - + " DELETE FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2}", - QueryType.GET_BATCH_TAGS.getParamName(0), - QueryType.GET_BATCH_TAGS.getParamName(1), - QueryType.GET_BATCH_TAGS.getParamName(2)); + "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); @@ -187,6 +199,7 @@ public class MySQLQueryProvider implements SQLQueryProvider { dataSource.setDatabaseName(dbName); dataSource.setUser(username); dataSource.setPassword(password); + dataSource.setAllowMultiQueries(true); return dataSource; } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java index 81e6cda..bc4ea26 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard.sqlserver.mappers; import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.protobuf.BulletinBoardAPI.BatchData; import org.springframework.jdbc.core.RowMapper; @@ -15,7 +16,11 @@ public class BatchDataMapper implements RowMapper { @Override public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException { - return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(1))).build(); + try { + return BatchData.parseFrom(rs.getBytes(1)); + } catch (InvalidProtocolBufferException e) { + return BatchData.getDefaultInstance(); + } } } diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 4799e0d..86a32de 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -12,18 +12,13 @@ import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.util.List; -import java.util.Random; +import java.util.*; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; import meerkat.crypto.concrete.ECDSASignature; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.FilterType; -import meerkat.protobuf.BulletinBoardAPI.MessageFilter; -import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; -import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.*; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; @@ -31,7 +26,7 @@ import static org.hamcrest.CoreMatchers.*; public class GenericBulletinBoardServerTest { protected BulletinBoardServer bulletinBoardServer; - private ECDSASignature signers[]; + private GenericBatchDigitalSignature signers[]; private ByteString[] signerIDs; private Random random; @@ -51,6 +46,8 @@ public class GenericBulletinBoardServerTest { private String[] tags; private byte[][] data; + private List completeBatches; + private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests /** @@ -71,10 +68,10 @@ public class GenericBulletinBoardServerTest { this.bulletinBoardServer = bulletinBoardServer; - signers = new ECDSASignature[2]; + signers = new GenericBatchDigitalSignature[2]; signerIDs = new ByteString[signers.length]; - signers[0] = new ECDSASignature(); - signers[1] = new ECDSASignature(); + signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); char[] password = KEYFILE_PASSWORD1.toCharArray(); @@ -121,6 +118,11 @@ public class GenericBulletinBoardServerTest { long end = threadBean.getCurrentThreadCpuTime(); System.err.println("Finished initializing GenericBulletinBoardServerTest"); System.err.println("Time of operation: " + (end - start)); + + // Initialize Batch variables + + completeBatches = new ArrayList(10); + } private byte randomByte(){ @@ -377,6 +379,182 @@ public class GenericBulletinBoardServerTest { System.err.println("Time of operation: " + (end - start)); } + + /** + * Tests that posting a message before opening a batch does not work + * @throws CommunicationException + */ + public void testBatchPostAfterClose() throws CommunicationException, SignatureException { + + final int BATCH_ID = 100; + + CompleteBatch completeBatch = new CompleteBatch(); + BoolMsg result; + + // Create data + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .setSignerId(signerIDs[1]) + .setBatchId(BATCH_ID) + .addTag("Test") + .build()); + + BatchData batchData = BatchData.newBuilder() + .setData(ByteString.copyFrom((new byte[] {1,2,3,4}))) + .build(); + + completeBatch.appendBatchData(batchData); + + signers[1].updateContent(completeBatch); + + completeBatch.setSignature(signers[1].sign()); + + // Begin batch + + result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage()); + + assertThat("Was not able to open batch", result.getValue(), is(true)); + + // Post data + + BatchMessage batchMessage = BatchMessage.newBuilder() + .setSignerId(signerIDs[1]) + .setBatchId(BATCH_ID) + .setData(batchData) + .build(); + + result = bulletinBoardServer.postBatchMessage(batchMessage); + + assertThat("Was not able to post batch message", result.getValue(), is(true)); + + // Close batch + + result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder() + .setBatchId(BATCH_ID) + .setBatchLength(1) + .setSig(completeBatch.getSignature()) + .build()); + + assertThat("Was not able to close batch", result.getValue(), is(true)); + + // Attempt to open batch again + + result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage()); + + assertThat("Was able to open a closed batch", result.getValue(), is(false)); + + // Attempt to add batch data + + result = bulletinBoardServer.postBatchMessage(batchMessage); + + assertThat("Was able to change a closed batch", result.getValue(), is(false)); + + } + + /** + * Posts a complete batch message + * @throws CommunicationException + */ + public void testPostBatch() throws CommunicationException, SignatureException { + + CompleteBatch completeBatch = new CompleteBatch(); + int currentBatch = completeBatches.size(); + + BoolMsg result; + + // Define batch data + + String[] tempBatchTags = new String[]{randomString(),randomString(),randomString()}; + byte[][] tempBatchData = new byte[Math.abs(randomByte())][]; + + for (int i = 0 ; i < tempBatchData.length ; i++) { + + tempBatchData[i] = new byte[Math.abs(randomByte())]; + + for (int j = 0; j < tempBatchData[i].length; j++) { + tempBatchData[i][j] = randomByte(); + } + + } + + // Begin batch + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .setSignerId(signerIDs[0]) + .setBatchId(currentBatch) + .addAllTag(Arrays.asList(tempBatchTags)) + .build()); + + result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage()); + + assertThat("Could not begin batch " + currentBatch, result.getValue(), is(true)); + + // Add batch data and randomize data posting order + + List dataOrder = new ArrayList(tempBatchData.length); + for (int i = 0 ; i < tempBatchData.length ; i++) { + dataOrder.add(i); + completeBatch.appendBatchData(BatchData.newBuilder() + .setData(ByteString.copyFrom(tempBatchData[i])) + .build()); + } + Collections.shuffle(dataOrder); + + // Post data + + for (int i = 0 ; i < tempBatchData.length ; i++) { + + int dataIndex = dataOrder.get(i); + + result = bulletinBoardServer.postBatchMessage(BatchMessage.newBuilder() + .setSignerId(signerIDs[0]) + .setBatchId(currentBatch) + .setSerialNum(dataIndex) + .setData(completeBatch.getBatchDataList().get(dataIndex)) + .build()); + + assertThat("Could not post batch data for batch ID " + currentBatch + " serial number " + dataIndex, + result.getValue(), is(true)); + + } + + // Close batch + + signers[0].updateContent(completeBatch); + completeBatch.setSignature(signers[0].sign()); + + result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder() + .setBatchId(currentBatch) + .setBatchLength(tempBatchData.length) + .setSig(completeBatch.getSignature()) + .build()); + + assertThat("Could not close batch " + currentBatch, result.getValue(), is(true)); + + // Update locally stored batches + completeBatches.add(completeBatch); + + } + + public void testReadBatch() throws CommunicationException { + + for (CompleteBatch completeBatch : completeBatches) { + + List batchDataList = + bulletinBoardServer.readBatch(BatchSpecificationMessage.newBuilder() + .setSignerId(completeBatch.getBeginBatchMessage().getSignerId()) + .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) + .setStartPosition(0) + .build()); + + assertThat("Non-matching batch data for batch " + completeBatch.getBeginBatchMessage().getBatchId(), + completeBatch.getBatchDataList().equals(batchDataList), is(true)); + + + + } + + } public void close(){ signers[0].clearSigningKey(); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java index e473931..42c11f7 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -111,6 +111,39 @@ public class 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()); + } + + } + @After public void close() { System.err.println("Starting to close MySQLBulletinBoardServerTest"); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java index 7fe3a43..0db1d3f 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -16,6 +16,7 @@ public interface BulletinBoardConstants { // Other Constants - public static final String BATCH_TAG = "Batch"; + public static final String BATCH_TAG = "@BATCH"; + public static final String BATCH_ID_TAG_PREFIX = "#"; } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 6deec77..19c57e3 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -22,6 +22,7 @@ public class CompleteBatch { } public CompleteBatch(BeginBatchMessage newBeginBatchMessage) { + this(); beginBatchMessage = newBeginBatchMessage; } @@ -47,6 +48,10 @@ public class CompleteBatch { return signature; } + public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { + this.beginBatchMessage = beginBatchMessage; + } + public void appendBatchData(BatchData newBatchData) { batchDataList.add(newBatchData); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java index 422e8b0..7174b42 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java @@ -3,7 +3,6 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.crypto.DigitalSignature; -import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; import meerkat.protobuf.BulletinBoardAPI.BatchData; import meerkat.protobuf.Crypto; @@ -11,10 +10,11 @@ import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.SignatureException; +import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.util.List; /** * Created by Arbel Deutsch Peled on 20-Dec-15. @@ -77,6 +77,12 @@ public class GenericBatchDigitalSignature implements BatchDigitalSignature{ return digitalSignature.verify(); } + @Override + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) + throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { + return digitalSignature.getPKCS12KeyStoreBuilder(keyStream, password); + } + @Override public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { digitalSignature.loadSigningCertificate(keyStoreBuilder); diff --git a/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java index e7b64e5..76c32a6 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java @@ -5,11 +5,13 @@ import com.google.protobuf.Message; import java.io.IOException; import java.io.InputStream; -import java.security.InvalidKeyException; import java.security.KeyStore; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.security.SignatureException; +import java.security.InvalidKeyException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; import static meerkat.protobuf.Crypto.*; /** @@ -71,6 +73,20 @@ public interface DigitalSignature { */ public boolean verify(); + /** + * Load a keystore from an input stream in PKCS12 format. + * + * @param keyStream + * @param password + * @return + * @throws IOException + * @throws CertificateException + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + */ + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) + throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException; + /** * Loads a private signing key. The keystore must include both the public and private * key parts. diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 28e4600..ab8084b 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -211,6 +211,7 @@ public class ECDSASignature implements DigitalSignature { * @throws KeyStoreException * @throws NoSuchAlgorithmException */ + @Override public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); From d643932ef966b3aa1f01c70e351bc15029bc9ad8 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 27 Dec 2015 12:04:37 +0200 Subject: [PATCH 006/106] Added H2 support for Batch messages --- bulletin-board-server/build.gradle | 5 ++ .../sqlserver/H2QueryProvider.java | 74 +++++++++++++++++++ .../H2BulletinBoardServerTest.java | 33 +++++++++ 3 files changed, 112 insertions(+) diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 63ba47d..21604d1 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -84,6 +84,11 @@ task myTest(type: Test) { outputs.upToDateWhen { false } } +task h2Test(type: Test) { + include '**/*H2*Test*' + outputs.upToDateWhen { false } +} + task dbTest(type: Test) { include '**/*H2*Test*' include '**/*MySQL*Test*' diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index d76601f..14bf9e2 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -7,6 +7,7 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; @@ -42,6 +43,11 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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"; @@ -55,6 +61,63 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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_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); } @@ -139,6 +202,14 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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)"); @@ -152,6 +223,9 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider List list = new LinkedList(); 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"); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java index ef19310..577c9be 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -107,6 +107,39 @@ public class 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"); From 141d286af26dc0663da74376f002e8b18ba6f005 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 17 Jan 2016 10:59:05 +0200 Subject: [PATCH 007/106] Dual-layered threaded BB Client. Supports basic functionality. Does not support Batch Messages yet. --- .../bulletinboard/BulletinClientJob.java | 82 ------- .../BulletinClientJobResult.java | 29 --- .../bulletinboard/BulletinClientWorker.java | 224 ++--------------- .../bulletinboard/MultiServerWorker.java | 104 ++++++++ .../SingleServerBulletinBoardClient.java | 228 ++++++++++++++++++ .../bulletinboard/SingleServerWorker.java | 39 +++ .../ThreadedBulletinBoardClient.java | 95 ++++++-- .../callbacks/ClientFutureCallback.java | 19 -- .../GetRedundancyFutureCallback.java | 38 --- .../callbacks/PostMessageFutureCallback.java | 44 ---- .../callbacks/ReadMessagesFutureCallback.java | 35 --- .../MultiServerGetRedundancyWorker.java | 74 ++++++ .../workers/MultiServerPostBatchWorker.java | 7 + .../workers/MultiServerPostMessageWorker.java | 72 ++++++ .../MultiServerReadMessagesWorker.java | 65 +++++ .../SingleServerGetRedundancyWorker.java | 79 ++++++ .../SingleServerPostMessageWorker.java | 61 +++++ .../SingleServerReadMessagesWorker.java | 68 ++++++ .../BulletinBoardClientIntegrationTest.java | 4 +- meerkat-common/build.gradle | 2 +- .../AsyncBulletinBoardClient.java | 44 +++- 21 files changed, 927 insertions(+), 486 deletions(-) delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerReadMessagesWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerGetRedundancyWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java deleted file mode 100644 index aca98d4..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java +++ /dev/null @@ -1,82 +0,0 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 09-Dec-15. - * - * This class specifies the job that is required of a Bulletin Board Client Worker - */ -public class BulletinClientJob { - - public static enum JobType{ - POST_MESSAGE, // Post a message to servers - READ_MESSAGES, // Read messages according to some given filter (any server will do) - GET_REDUNDANCY // Check the redundancy of a specific message in the databases - } - - private List serverAddresses; - - private int minServers; // The minimal number of servers the job must be successful on for the job to be completed - - private final JobType jobType; - - private final Message payload; // The information associated with the job type - - private int maxRetry; // Number of retries for this job; set to -1 for infinite retries - - public BulletinClientJob(List serverAddresses, int minServers, JobType jobType, Message payload, int maxRetry) { - this.serverAddresses = serverAddresses; - this.minServers = minServers; - this.jobType = jobType; - this.payload = payload; - this.maxRetry = maxRetry; - } - - public void updateServerAddresses(List newServerAdresses) { - this.serverAddresses = newServerAdresses; - } - - public List getServerAddresses() { - return serverAddresses; - } - - public int getMinServers() { - return minServers; - } - - public JobType getJobType() { - return jobType; - } - - public Message getPayload() { - return payload; - } - - public int getMaxRetry() { - return maxRetry; - } - - public void shuffleAddresses() { - Collections.shuffle(serverAddresses); - } - - public void decMinServers(){ - minServers--; - } - - public void decMaxRetry(){ - if (maxRetry > 0) { - maxRetry--; - } - } - - public boolean isRetry(){ - return (maxRetry != 0); - } - -} \ No newline at end of file diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java deleted file mode 100644 index be0501b..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java +++ /dev/null @@ -1,29 +0,0 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; - -/** - * Created by Arbel Deutsch Peled on 09-Dec-15. - * - * This class contains the end status and result of a Bulletin Board Client Job. - */ -public final class BulletinClientJobResult { - - private final BulletinClientJob job; // Stores the job the result refers to - - private final Message result; // The result of the job; valid only if success==true - - public BulletinClientJobResult(BulletinClientJob job, Message result) { - this.job = job; - this.result = result; - } - - public BulletinClientJob getJob() { - return job; - } - - public Message getResult() { - return result; - } - -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index f03ab31..dba596b 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -1,218 +1,38 @@ package meerkat.bulletinboard; -import com.google.protobuf.Message; -import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.rest.Constants; -import meerkat.rest.ProtobufMessageBodyReader; -import meerkat.rest.ProtobufMessageBodyWriter; -import static meerkat.bulletinboard.BulletinBoardConstants.*; - -import javax.ws.rs.ProcessingException; -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 java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; - /** * Created by Arbel Deutsch Peled on 09-Dec-15. * - * This class implements the actual communication with the Bulletin Board Servers. + * This class handles bulletin client work. * It is meant to be used in a multi-threaded environment. */ -//TODO: Maybe make this abstract and inherit from it. -public class BulletinClientWorker implements Callable { +public abstract class BulletinClientWorker { - private final BulletinClientJob job; // The requested job to be handled + protected IN payload; // Payload of the job - public BulletinClientWorker(BulletinClientJob job){ - this.job = 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; } - // This resource enabled creation of a single Client per thread. - private static final ThreadLocal clientLocal = - new ThreadLocal () { - @Override protected Client initialValue() { - Client client; - client = ClientBuilder.newClient(); - client.register(ProtobufMessageBodyReader.class); - client.register(ProtobufMessageBodyWriter.class); + public IN getPayload() { + return payload; + } - return client; - } - }; - - // This resource enables creation of a single Digest per thread. - private static final ThreadLocal digestLocal = - new ThreadLocal () { - @Override protected Digest initialValue() { - Digest digest; - digest = new SHA256Digest(); //TODO: Make this generic. - - return digest; - } - }; - - /** - * This method carries out the actual communication with the servers via HTTP Post - * It accesses the servers according to the job it received and updates said job as it goes - * The method will only iterate once through the server list, removing servers from the list when they are no longer required - * In a POST_MESSAGE job: successful post to a server results in removing the server from the list - * In a GET_REDUNDANCY job: no server is removed from the list and the (absolute) number of servers in which the message was found is returned - * In a READ_MESSAGES job: successful retrieval from any server terminates the method and returns the received values; The list is not changed - * @return The original job, modified to fit the current state and the required output (if any) of the operation - * @throws IllegalArgumentException - * @throws CommunicationException - */ - public BulletinClientJobResult call() throws IllegalArgumentException, CommunicationException{ - - Client client = clientLocal.get(); - Digest digest = digestLocal.get(); - - WebTarget webTarget; - Response response; - - String requestPath; - Message msg; - - List serverAddresses = new LinkedList(job.getServerAddresses()); - - Message payload = job.getPayload(); - - BulletinBoardMessageList msgList; - - int count = 0; // Used to count number of servers which contain the required message in a GET_REDUNDANCY request. - - job.shuffleAddresses(); // This is done to randomize the order of access to servers primarily for READ operations - - // Prepare the request. - switch(job.getJobType()) { - - case POST_MESSAGE: - // Make sure the payload is a BulletinBoardMessage - if (!(payload instanceof BulletinBoardMessage)) { - throw new IllegalArgumentException("Cannot post an object that is not an instance of BulletinBoardMessage"); - } - - msg = payload; - requestPath = POST_MESSAGE_PATH; - break; - - case READ_MESSAGES: - // Make sure the payload is a MessageFilterList - if (!(payload instanceof MessageFilterList)) { - throw new IllegalArgumentException("Read failed: an instance of MessageFilterList is required as payload for a READ_MESSAGES operation"); - } - - msg = payload; - requestPath = READ_MESSAGES_PATH; - break; - - case GET_REDUNDANCY: - // Make sure the payload is a MessageId - if (!(payload instanceof MessageID)) { - throw new IllegalArgumentException("Cannot search for an object that is not an instance of MessageID"); - } - - requestPath = READ_MESSAGES_PATH; - - msg = MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.MSG_ID) - .setId(((MessageID) payload).getID()) - .build() - ).build(); - - break; - - default: - throw new IllegalArgumentException("Unsupported job type"); - - } - - // Iterate through servers - - Iterator addressIterator = serverAddresses.iterator(); - - while (addressIterator.hasNext()) { - - // Send request to Server - String address = addressIterator.next(); - webTarget = client.target(address).path(BULLETIN_BOARD_SERVER_PATH).path(requestPath); - response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); - - // Retrieve answer - switch(job.getJobType()) { - - case POST_MESSAGE: - try { - - response.readEntity(BoolMsg.class); // If a BoolMsg entity is returned: the post was successful - addressIterator.remove(); // Post to this server succeeded: remove server from list - job.decMinServers(); - - } catch (ProcessingException | IllegalStateException e) {} // Post to this server failed: retry next time - finally { - response.close(); - } - break; - - case GET_REDUNDANCY: - try { - msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful - - if (msgList.getMessageList().size() > 0){ // Message was found in the server. - count++; - } - } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server - finally { - response.close(); - } - break; - - case READ_MESSAGES: - try { - msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful - return new BulletinClientJobResult(job, msgList); // Return the result - } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server - finally { - response.close(); - } - break; - - } - - } - - // Return result (if haven't done so yet) - switch(job.getJobType()) { - - case POST_MESSAGE: - // The job now contains the information required to ascertain whether enough server posts have succeeded - // It will also contain the list of servers in which the post was not successful - job.updateServerAddresses(serverAddresses); - return new BulletinClientJobResult(job, null); - - case GET_REDUNDANCY: - // Return the number of servers in which the message was found - // The job now contains the list of these servers - return new BulletinClientJobResult(job, IntMsg.newBuilder().setValue(count).build()); - - case READ_MESSAGES: - // A successful operation would have already returned an output - // Therefore: no server access was successful - throw new CommunicationException("Could not access any server"); - - default: // This is required for successful compilation - throw new IllegalArgumentException("Unsupported job type"); + public int getMaxRetry() { + return maxRetry; + } + public void decMaxRetry(){ + if (maxRetry > 0) { + maxRetry--; } } + + public boolean isRetry(){ + return (maxRetry != 0); + } + } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java new file mode 100644 index 0000000..8db836f --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java @@ -0,0 +1,104 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by Arbel Deutsch Peled on 09-Dec-15. + * + * This is a general class for handling multi-server work + * It utilizes Single Server Clients to perform the actual per-server work + */ +public abstract class MultiServerWorker extends BulletinClientWorker implements Runnable, ClientCallback{ + + private List clients; + + protected AtomicInteger minServers; // The minimal number of servers the job must be successful on for the job to be completed + + protected AtomicInteger maxFailedServers; // The maximal number of allowed server failures + + private AtomicBoolean returnedResult; + + private ClientCallback clientCallback; + + /** + * Constructor + * @param clients contains a list of Single Server clients to handle requests + * @param shuffleClients is a boolean stating whether or not it is needed to shuffle the clients + * @param minServers is the minimal amount of servers needed in order to successfully complete the job + * @param payload is the payload for the job + * @param maxRetry is the maximal per-server retry count + * @param clientCallback contains the callback methods used to report the result back to the client + */ + public MultiServerWorker(List clients, boolean shuffleClients, + int minServers, IN payload, int maxRetry, + ClientCallback clientCallback) { + + super(payload,maxRetry); + + this.clients = clients; + if (shuffleClients){ + Collections.shuffle(clients); + } + + this.minServers = new AtomicInteger(minServers); + maxFailedServers = new AtomicInteger(clients.size() - minServers); + this.clientCallback = clientCallback; + + returnedResult = new AtomicBoolean(false); + + } + + /** + * Constructor overload without client shuffling + */ + public MultiServerWorker(List clients, + int minServers, IN payload, int maxRetry, + ClientCallback clientCallback) { + + this(clients, false, minServers, payload, maxRetry, clientCallback); + + } + + /** + * Used to report a successful operation to the client + * Only reports once to the client + * @param result is the result + */ + protected void succeed(OUT result){ + if (returnedResult.compareAndSet(false, true)) { + clientCallback.handleCallback(result); + } + } + + /** + * Used to report a failed operation to the client + * Only reports once to the client + * @param t contains the error/exception that occurred + */ + protected void fail(Throwable t){ + if (returnedResult.compareAndSet(false, true)) { + clientCallback.handleFailure(t); + } + } + + /** + * Used by implementations to get a Single Server Client iterator + * @return the requested iterator + */ + protected Iterator getClientIterator() { + return clients.iterator(); + } + + protected int getClientNumber() { + return clients.size(); + } + +} \ No newline at end of file diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java new file mode 100644 index 0000000..e92f35b --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -0,0 +1,228 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListeningScheduledExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.ByteString; +import meerkat.bulletinboard.workers.SingleServerGetRedundancyWorker; +import meerkat.bulletinboard.workers.SingleServerPostMessageWorker; +import meerkat.bulletinboard.workers.SingleServerReadMessagesWorker; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Voting.BulletinBoardClientParams; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Created by Arbel Deutsch Peled on 28-Dec-15. + * + * This class implements the asynchronous Bulletin Board Client interface + * It only handles a single Bulletin Board Server + * If the list of servers contains more than one server: the server actually used is the first one + * The class further implements a delayed access to the server after a communication error occurs + */ +public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient { + + private final int MAX_RETRIES = 10; + + protected ListeningScheduledExecutorService executorService; + + private long lastServerErrorTime; + + protected final long failDelayInMilliseconds; + + /** + * Notify the client that a job has failed + * This makes new scheduled jobs be scheduled for a later time (after the given delay) + */ + protected void fail() { + + // Update last fail time + lastServerErrorTime = System.currentTimeMillis(); + + } + + /** + * This method adds a worker to the scheduled queue of the threadpool + * If the server is in an accessible state: the job is submitted for immediate handling + * If the server is not accessible: the job is scheduled for a later time + * @param worker is the worker that should be scheduled for work + * @param callback is the class containing callbacks for handling job completion/failure + */ + protected void scheduleWorker(SingleServerWorker worker, FutureCallback callback){ + + long timeSinceLastServerError = System.currentTimeMillis() - lastServerErrorTime; + + if (timeSinceLastServerError >= failDelayInMilliseconds) { + + // Schedule for immediate processing + Futures.addCallback(executorService.submit(worker), callback); + + } else { + + // Schedule for processing immediately following delay expiry + Futures.addCallback(executorService.schedule( + worker, + failDelayInMilliseconds - timeSinceLastServerError, + TimeUnit.MILLISECONDS), + callback); + + } + + } + + /** + * Inner class for handling simple operation results and retrying if needed + */ + class RetryCallback implements FutureCallback { + + private SingleServerWorker worker; + private ClientCallback clientCallback; + + public RetryCallback(SingleServerWorker worker, ClientCallback clientCallback) { + this.worker = worker; + this.clientCallback = clientCallback; + } + + @Override + public void onSuccess(T result) { + clientCallback.handleCallback(result); + } + + @Override + public void onFailure(Throwable t) { + + // Notify client about failure + fail(); + + // Check if another attempt should be made + + worker.decMaxRetry(); + + if (worker.isRetry()) { + // Perform another attempt + scheduleWorker(worker, this); + } else { + // No more retries: notify caller about failure + clientCallback.handleFailure(t); + } + + } + + } + + + public SingleServerBulletinBoardClient(int threadPoolSize, long failDelayInMilliseconds) { + + executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)); + + this.failDelayInMilliseconds = failDelayInMilliseconds; + + // Set server error time to a time sufficiently in the past to make new jobs go through + lastServerErrorTime = System.currentTimeMillis() - failDelayInMilliseconds; + + } + + /** + * Stores database location, initializes the web Client and + * @param clientParams contains the data needed to access the DBs + */ + @Override + public void init(BulletinBoardClientParams clientParams) { + + // Perform usual setup + super.init(clientParams); + + // Remove all but first DB address + String dbAddress = meerkatDBs.get(0); + meerkatDBs = new LinkedList(); + meerkatDBs.add(dbAddress); + + } + + @Override + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback) { + + // Create worker with redundancy 1 and MAX_RETRIES retries + SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(meerkatDBs.get(0), msg, MAX_RETRIES); + + // Submit worker and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); + + // Calculate the correct message ID and return it + digest.reset(); + digest.update(msg.getMsg()); + return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); + + } + + @Override + public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { + return null; + } + + @Override + public void beginBatch(byte[] signerId, int batchId, List tagList, ClientCallback callback) { + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback) { + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + + } + + @Override + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + + } + + @Override + public void getRedundancy(MessageID id, ClientCallback callback) { + + // Create worker with no retries + SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(meerkatDBs.get(0), id, 1); + + // Submit job and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); + + } + + @Override + public void readMessages(MessageFilterList filterList, ClientCallback> callback) { + + // Create job with no retries + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); + + // Submit job and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); + + } + + @Override + public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { + + } + + @Override + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) { + + } + + @Override + public void close() { + + super.close(); + + executorService.shutdown(); + + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java new file mode 100644 index 0000000..82ca886 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java @@ -0,0 +1,39 @@ +package meerkat.bulletinboard; + +import meerkat.rest.ProtobufMessageBodyReader; +import meerkat.rest.ProtobufMessageBodyWriter; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import java.util.concurrent.Callable; + +/** + * Created by Arbel Deutsch Peled on 02-Jan-16. + */ +public abstract class SingleServerWorker extends BulletinClientWorker implements Callable{ + + // This resource enabled creation of a single Client per thread. + protected static final ThreadLocal clientLocal = + new ThreadLocal () { + @Override protected Client initialValue() { + Client client; + client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + + return client; + } + }; + + protected String serverAddress; + + public SingleServerWorker(String serverAddress, IN payload, int maxRetry) { + super(payload, maxRetry); + this.serverAddress = serverAddress; + } + + public String getServerAddress() { + return serverAddress; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 71d852e..ce7a01e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -1,15 +1,17 @@ package meerkat.bulletinboard; -import com.google.common.util.concurrent.*; import com.google.protobuf.ByteString; -import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; -import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; -import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; + +import meerkat.bulletinboard.workers.MultiServerGetRedundancyWorker; +import meerkat.bulletinboard.workers.MultiServerPostMessageWorker; +import meerkat.bulletinboard.workers.MultiServerReadMessagesWorker; import meerkat.comm.CommunicationException; 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; @@ -22,10 +24,19 @@ import java.util.concurrent.TimeUnit; */ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient { - private final static int THREAD_NUM = 10; - ListeningExecutorService listeningExecutor; + // Executor service for handling jobs + private final static int JOBS_THREAD_NUM = 5; + ExecutorService executorService; + // Per-server clients + List clients; + + 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 int minAbsoluteRedundancy; @@ -42,7 +53,16 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * clientParams.getBulletinBoardAddressCount()); - listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUM)); + 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); + client.init(BulletinBoardClientParams.newBuilder() + .addBulletinBoardAddress(address) + .build()); + clients.add(client); + } } @@ -54,28 +74,52 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple * @throws CommunicationException */ @Override - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback){ + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback){ // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.POST_MESSAGE, msg, -1); + MultiServerPostMessageWorker worker = + new MultiServerPostMessageWorker(clients, minAbsoluteRedundancy, msg, POST_MESSAGE_RETRY_NUM, callback); - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new PostMessageFutureCallback(listeningExecutor, callback)); + // Submit job + executorService.submit(worker); // Calculate the correct message ID and return it digest.reset(); digest.update(msg.getMsg()); return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); + } @Override - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback) { - return null; //TODO: Implement + public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { + + return null; // TODO: write this + } @Override - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { - return null; //TODO: Implement + public void beginBatch(byte[] signerId, int batchId, List tagList, ClientCallback callback) { + // TODO: write this + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback) { + + // TODO: write this + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + + postBatchData(signerId, batchId, batchDataList, 0, callback); // Write batch from beginning + + } + + @Override + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + // TODO: write this } /** @@ -88,10 +132,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple public void getRedundancy(MessageID id, ClientCallback callback) { // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.GET_REDUNDANCY, id, 1); + MultiServerGetRedundancyWorker worker = + new MultiServerGetRedundancyWorker(clients, minAbsoluteRedundancy, id, GET_REDUNDANCY_RETRY_NUM, callback); - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new GetRedundancyFutureCallback(listeningExecutor, callback)); + // Submit job + executorService.submit(worker); } @@ -104,11 +149,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple public void readMessages(MessageFilterList filterList, ClientCallback> callback) { // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.READ_MESSAGES, - filterList, READ_MESSAGES_RETRY_NUM); + MultiServerReadMessagesWorker worker = + new MultiServerReadMessagesWorker(clients, minAbsoluteRedundancy, filterList, READ_MESSAGES_RETRY_NUM, callback); - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new ReadMessagesFutureCallback(listeningExecutor, callback)); + // Submit job + executorService.submit(worker); } @@ -127,9 +172,9 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple super.close(); try { - listeningExecutor.shutdown(); - while (! listeningExecutor.isShutdown()) { - listeningExecutor.awaitTermination(10, TimeUnit.SECONDS); + executorService.shutdown(); + while (! executorService.isShutdown()) { + executorService.awaitTermination(10, TimeUnit.SECONDS); } } catch (InterruptedException e) { System.err.println(e.getCause() + " " + e.getMessage()); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java deleted file mode 100644 index 54cc63a..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java +++ /dev/null @@ -1,19 +0,0 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinClientJobResult; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public abstract class ClientFutureCallback implements FutureCallback { - - protected ListeningExecutorService listeningExecutor; - - ClientFutureCallback(ListeningExecutorService listeningExecutor) { - this.listeningExecutor = listeningExecutor; - } - -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java deleted file mode 100644 index 719428f..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java +++ /dev/null @@ -1,38 +0,0 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.AsyncBulletinBoardClient.*; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class GetRedundancyFutureCallback extends ClientFutureCallback { - - private ClientCallback callback; - - public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, - ClientCallback callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - int absoluteRedundancy = ((IntMsg) result.getResult()).getValue(); - int totalServers = result.getJob().getServerAddresses().size(); - - callback.handleCallback( ((float) absoluteRedundancy) / ((float) totalServers) ); - - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java deleted file mode 100644 index abd4247..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java +++ /dev/null @@ -1,44 +0,0 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.AsyncBulletinBoardClient.*; -import meerkat.bulletinboard.BulletinClientJob; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; - - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class PostMessageFutureCallback extends ClientFutureCallback { - - private ClientCallback callback; - - public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, - ClientCallback callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - BulletinClientJob job = result.getJob(); - - job.decMaxRetry(); - - // If redundancy is below threshold: retry - if (job.getMinServers() > 0 && job.isRetry()) { - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), this); - } - - callback.handleCallback(null); - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java deleted file mode 100644 index 808b7a6..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java +++ /dev/null @@ -1,35 +0,0 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.AsyncBulletinBoardClient.*; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class ReadMessagesFutureCallback extends ClientFutureCallback { - - private ClientCallback> callback; - - public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, - ClientCallback> callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - callback.handleCallback(((BulletinBoardAPI.BulletinBoardMessageList) result.getResult()).getMessageList()); - - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java new file mode 100644 index 0000000..4d5e7f2 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java @@ -0,0 +1,74 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.MultiServerWorker; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerGetRedundancyWorker extends MultiServerWorker { + + private AtomicInteger serversContainingMessage; + private AtomicInteger totalContactedServers; + + public MultiServerGetRedundancyWorker(List clients, + int minServers, MessageID payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); // Shuffle clients on creation to balance load + + serversContainingMessage = new AtomicInteger(0); + totalContactedServers = new AtomicInteger(0); + + } + + /** + * This method carries out the actual communication with the servers via HTTP Post + * It accesses the servers in a random order until one answers it + * Successful retrieval from any server terminates the method and returns the received values; The list is not changed + * @return The original job and the list of messages found in the first server that answered the query + * @throws CommunicationException + */ + public void run(){ + + Iterator clientIterator = getClientIterator(); + + // Iterate through clients + + while (clientIterator.hasNext()) { + + SingleServerBulletinBoardClient client = clientIterator.next(); + + // Send request to client + client.getRedundancy(payload,this); + + } + + } + + @Override + public void handleCallback(Float result) { + + if (result > 0.5) { + serversContainingMessage.incrementAndGet(); + } + + if (totalContactedServers.incrementAndGet() >= getClientNumber()){ + succeed(new Float(((float) serversContainingMessage.get()) / ((float) getClientNumber()) )); + } + + } + + @Override + public void handleFailure(Throwable t) { + handleCallback(new Float(0.0)); + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java new file mode 100644 index 0000000..cfc34e7 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java @@ -0,0 +1,7 @@ +package meerkat.bulletinboard.workers; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerPostBatchWorker { +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java new file mode 100644 index 0000000..dcdc82a --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java @@ -0,0 +1,72 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.MultiServerWorker; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import java.util.Iterator; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerPostMessageWorker extends MultiServerWorker { + + public MultiServerPostMessageWorker(List clients, + int minServers, BulletinBoardMessage payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + /** + * This method carries out the actual communication with the servers via HTTP Post + * It accesses the servers one by one and tries to post the payload to each in turn + * The method will only iterate once through the server list + * Successful post to a server results in removing the server from the list + * @return The original job, but with a modified server list + * @throws CommunicationException + */ + public void run() { + + WebTarget webTarget; + Response response; + + int count = 0; // Used to count number of servers which contain the required message in a GET_REDUNDANCY request. + + // Iterate through servers + + Iterator clientIterator = getClientIterator(); + + while (clientIterator.hasNext()) { + + // Send request to Server + SingleServerBulletinBoardClient client = clientIterator.next(); + + client.postMessage(payload, this); + + } + + } + + @Override + public void handleCallback(Boolean result) { + if (result){ + if (minServers.decrementAndGet() <= 0){ + succeed(Boolean.TRUE); + } + } + } + + @Override + public void handleFailure(Throwable t) { + if (maxFailedServers.decrementAndGet() < 0){ + fail(t); + } + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerReadMessagesWorker.java new file mode 100644 index 0000000..bf19526 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerReadMessagesWorker.java @@ -0,0 +1,65 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.MultiServerWorker; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.Iterator; +import java.util.List; + + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerReadMessagesWorker extends MultiServerWorker>{ + + private Iterator clientIterator; + + public MultiServerReadMessagesWorker(List clients, + int minServers, MessageFilterList payload, int maxRetry, + ClientCallback> clientCallback) { + + super(clients, true, minServers, payload, maxRetry, clientCallback); // Shuffle clients on creation to balance load + + clientIterator = getClientIterator(); + + } + + /** + * This method carries out the actual communication with the servers via HTTP Post + * It accesses the servers in a random order until one answers it + * Successful retrieval from any server terminates the method and returns the received values; The list is not changed + * @return The original job and the list of messages found in the first server that answered the query + * @throws CommunicationException + */ + public void run(){ + + // Iterate through servers + + if (clientIterator.hasNext()) { + + // Send request to Server + SingleServerBulletinBoardClient client = clientIterator.next(); + + // Retrieve answer + client.readMessages(payload,this); + + } else { + fail(new CommunicationException("Could not contact any server")); + } + + } + + @Override + public void handleCallback(List msg) { + succeed(msg); + } + + @Override + public void handleFailure(Throwable t) { + run(); // Retry with next server + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerGetRedundancyWorker.java new file mode 100644 index 0000000..a02da03 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerGetRedundancyWorker.java @@ -0,0 +1,79 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.SingleServerWorker; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; +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.READ_MESSAGES_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class SingleServerGetRedundancyWorker extends SingleServerWorker { + + public SingleServerGetRedundancyWorker(String serverAddress, MessageID payload, int maxRetry) { + super(serverAddress, payload, maxRetry); + } + + /** + * This method carries out the actual communication with the server via HTTP Post + * It queries the server for a message with the given ID + * @return TRUE if the message exists in the server and FALSE otherwise + * @throws CommunicationException if the server does not return a valid answer + */ + public Float call() throws CommunicationException{ + + Client client = clientLocal.get(); + + WebTarget webTarget; + Response response; + + MessageFilterList msgFilterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(payload.getID()) + .build() + ).build(); + + // Send request to Server + + webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH); + response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msgFilterList, Constants.MEDIATYPE_PROTOBUF)); + + // Retrieve answer + + try { + + // If a BulletinBoardMessageList is returned: the read was successful + BulletinBoardMessageList msgList = response.readEntity(BulletinBoardMessageList.class); + + if (msgList.getMessageList().size() > 0){ + // Message exists in the server + return new Float(1.0); + } + else { + // Message does not exist in the server + return new Float(0.0); + } + + } catch (ProcessingException | IllegalStateException e) { + + // Read failed + throw new CommunicationException("Server access failed"); + + } + finally { + response.close(); + } + + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java new file mode 100644 index 0000000..ee9fd3f --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java @@ -0,0 +1,61 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.SingleServerWorker; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.BoolMsg; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +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.POST_MESSAGE_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + * Tries to contact server once and perform a post operation + */ +public class SingleServerPostMessageWorker extends SingleServerWorker { + + public SingleServerPostMessageWorker(String serverAddress, BulletinBoardMessage payload, int maxRetry) { + super(serverAddress, payload, maxRetry); + } + + /** + * This method carries out the actual communication with the server via HTTP Post + * It accesses the server and tries to post the payload to it + * Successful post to a server results + * @return TRUE if the operation is successful + * @throws CommunicationException if the operation is unseccessful + */ + public Boolean call() throws CommunicationException{ + + Client client = clientLocal.get(); + + WebTarget webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);; + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post( + Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF)); + + try { + + // If a BoolMsg entity is returned: the post was successful + response.readEntity(BoolMsg.class); + return Boolean.TRUE; + + } catch (ProcessingException | IllegalStateException e) { + + // Post to this server failed + throw new CommunicationException("Could not contact the server"); + + } + finally { + response.close(); + } + + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java new file mode 100644 index 0000000..f8975cb --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java @@ -0,0 +1,68 @@ +package meerkat.bulletinboard.workers; + +import meerkat.bulletinboard.SingleServerWorker; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +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 java.util.List; + +import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; +import static meerkat.bulletinboard.BulletinBoardConstants.READ_MESSAGES_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class SingleServerReadMessagesWorker extends SingleServerWorker> { + + public SingleServerReadMessagesWorker(String serverAddress, MessageFilterList payload, int maxRetry) { + super(serverAddress, payload, maxRetry); + } + + /** + * This method carries out the actual communication with the server via HTTP Post + * Upon successful retrieval from the server the method returns the received values + * @return The list of messages returned by the server + * @throws CommunicationException if the server's response is invalid + */ + public List call() throws CommunicationException{ + + Client client = clientLocal.get(); + + WebTarget webTarget; + Response response; + + // Send request to Server + webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_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(BulletinBoardMessageList.class).getMessageList(); + + } catch (ProcessingException | IllegalStateException e) { + + // Read failed + throw new CommunicationException("Could not contact the server"); + + } + finally { + response.close(); + } + + + } + +} diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index d7ae69c..7bdbe08 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -32,10 +32,10 @@ public class BulletinBoardClientIntegrationTest { jobSemaphore.release(); } - private class PostCallback implements ClientCallback{ + private class PostCallback implements ClientCallback{ @Override - public void handleCallback(Object msg) { + public void handleCallback(Boolean msg) { System.err.println("Post operation completed"); jobSemaphore.release(); } diff --git a/meerkat-common/build.gradle b/meerkat-common/build.gradle index c510e0a..3783531 100644 --- a/meerkat-common/build.gradle +++ b/meerkat-common/build.gradle @@ -46,7 +46,7 @@ dependencies { compile 'com.google.protobuf:protobuf-java:3.+' // ListeningExecutor - compile 'com.google.guava:guava:11.0.+' + compile 'com.google.guava:guava:15.0' // Crypto compile 'org.factcenter.qilin:qilin:1.2+' diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 1663f7a..00bd2ac 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.Signature; import java.util.List; @@ -24,23 +25,48 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a class containing methods to handle the result of the operation * @return a unique message ID for the message, that can be later used to retrieve the batch */ - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); /** - * This method allows for sending large messages as a batch to the bulletin board + * Perform an end-to-end post of a signed batch message + * @param completeBatch contains all the data of the batch including the meta-data and the signature + * @param callback is a class containing methods to handle the result of the operation + * @return a unique identifier for the batch message + */ + public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback); + + /** + * This message informs the server about the existence of a new batch message and supplies it with the tags associated with it * @param signerId is the canonical form for the ID of the sender of this batch * @param batchId is a unique (per signer) ID for this batch - * @param batchDataList is the (canonically ordered) list of data comprising the batch message - * @param startPosition is the location (in the batch) of the first entry in batchDataList (optionally used to continue interrupted post operations) - * @param callback is a callback function class for handling results of the operation - * @return a unique message ID for the entire message, that can be later used to retrieve the batch + * @param tagList is a list of tags that belong to the batch message */ - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + public void beginBatch(byte[] signerId, int batchId, List tagList, ClientCallback callback); /** - * Overloading of the postBatch method in which startPosition is set to the default value 0 + * This method posts batch data into an (assumed to be open) batch + * It does not close the batch + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param batchDataList is the (canonically ordered) list of data comprising the entire batch message (not just the portion to be written) + * @param startPosition is the location (in the batch) of the first entry in batchDataList + * (optionally used to continue interrupted post operations) + * @param callback is a callback function class for handling results of the operation */ - public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + public void postBatchData(byte[] signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatchData method in which startPosition is set to the default value 0 + */ + public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + + /** + * Attempts to close a batch message + * @param closeBatchMessage contains the data required to close the batch + * @param callback is a callback function class for handling results of the operation + */ + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback); /** * Check how "safe" a given message is in an asynchronous manner From 3fed32f9e62d83cc1a67f7a463032a86b46eb30e Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 17 Jan 2016 19:57:45 +0200 Subject: [PATCH 008/106] First (untested) version of BB Client with full batch support --- .../bulletinboard/BatchDataContainer.java | 25 +++ .../SingleServerBulletinBoardClient.java | 145 ++++++++++++++++-- .../ThreadedBulletinBoardClient.java | 87 +++++++++-- .../workers/MultiServerPostBatchWorker.java | 7 - .../MultiServerBeginBatchWorker.java | 28 ++++ .../MultiServerCloseBatchWorker.java | 28 ++++ .../MultiServerGenericPostWorker.java} | 13 +- .../MultiServerGenericReadWorker.java} | 19 +-- .../MultiServerGetRedundancyWorker.java | 2 +- .../MultiServerPostBatchDataWorker.java | 28 ++++ .../MultiServerPostBatchWorker.java | 28 ++++ .../MultiServerPostMessageWorker.java | 28 ++++ .../MultiServerReadBatchWorker.java | 30 ++++ .../MultiServerReadMessagesWorker.java | 29 ++++ .../SingleServerBeginBatchWorker.java | 17 ++ .../SingleServerCloseBatchWorker.java | 17 ++ .../SingleServerGenericPostWorker.java} | 15 +- .../SingleServerGetRedundancyWorker.java | 2 +- .../SingleServerPostBatchWorker.java | 17 ++ .../SingleServerPostMessageWorker.java | 17 ++ .../SingleServerReadBatchWorker.java | 119 ++++++++++++++ .../SingleServerReadMessagesWorker.java | 2 +- .../webapp/BulletinBoardWebApp.java | 4 + .../AsyncBulletinBoardClient.java | 34 ++-- .../bulletinboard/BulletinBoardConstants.java | 3 +- .../bulletinboard/GenericBatchDigest.java | 7 +- .../src/main/java/meerkat/crypto/Digest.java | 7 + .../meerkat/crypto/concrete/SHA256Digest.java | 6 + 28 files changed, 692 insertions(+), 72 deletions(-) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java delete mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{MultiServerPostMessageWorker.java => multiserver/MultiServerGenericPostWorker.java} (82%) rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{MultiServerReadMessagesWorker.java => multiserver/MultiServerGenericReadWorker.java} (68%) rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{ => multiserver}/MultiServerGetRedundancyWorker.java (97%) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerBeginBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{SingleServerPostMessageWorker.java => singleserver/SingleServerGenericPostWorker.java} (76%) rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{ => singleserver}/SingleServerGetRedundancyWorker.java (98%) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerPostBatchWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerPostMessageWorker.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/{ => singleserver}/SingleServerReadMessagesWorker.java (97%) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java new file mode 100644 index 0000000..53f4870 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java @@ -0,0 +1,25 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.BulletinBoardAPI.BatchData; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 17-Jan-16. + * Used to store the complete data required for sending a batch data list inside a single object + */ +public class BatchDataContainer { + + public final byte[] signerId; + public final int batchId; + public final List batchDataList; + public final int startPosition; + + public BatchDataContainer(byte[] signerId, int batchId, List batchDataList, int startPosition) { + this.signerId = signerId; + this.batchId = batchId; + this.batchDataList = batchDataList; + this.startPosition = startPosition; + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index e92f35b..9c211fd 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -5,9 +5,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; -import meerkat.bulletinboard.workers.SingleServerGetRedundancyWorker; -import meerkat.bulletinboard.workers.SingleServerPostMessageWorker; -import meerkat.bulletinboard.workers.SingleServerReadMessagesWorker; +import meerkat.bulletinboard.workers.singleserver.*; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.BulletinBoardClientParams; @@ -30,6 +28,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i protected ListeningScheduledExecutorService executorService; + protected BatchDigest batchDigest; + private long lastServerErrorTime; protected final long failDelayInMilliseconds; @@ -136,6 +136,9 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Perform usual setup super.init(clientParams); + // Wrap the Digest into a BatchDigest + batchDigest = new GenericBatchDigest(digest); + // Remove all but first DB address String dbAddress = meerkatDBs.get(0); meerkatDBs = new LinkedList(); @@ -153,19 +156,124 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i scheduleWorker(worker, new RetryCallback(worker, callback)); // Calculate the correct message ID and return it - digest.reset(); - digest.update(msg.getMsg()); - return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); + batchDigest.reset(); + batchDigest.update(msg.getMsg()); + return batchDigest.digestAsMessageID(); } + private class PostBatchDataCallback implements ClientCallback { + + private CompleteBatch completeBatch; + ClientCallback callback; + + public PostBatchDataCallback(CompleteBatch completeBatch, ClientCallback callback) { + this.completeBatch = completeBatch; + this.callback = callback; + } + + @Override + public void handleCallback(Boolean msg) { + closeBatch( + CloseBatchMessage.newBuilder() + .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) + .setSig(completeBatch.getSignature()) + .setBatchLength(completeBatch.getBatchDataList().size()) + .build(), + callback + ); + } + + @Override + public void handleFailure(Throwable t) { + callback.handleFailure(t); + } + + } + + private class BeginBatchCallback implements ClientCallback { + + private CompleteBatch completeBatch; + ClientCallback callback; + + public BeginBatchCallback(CompleteBatch completeBatch, ClientCallback callback) { + this.completeBatch = completeBatch; + this.callback = callback; + } + + @Override + public void handleCallback(Boolean msg) { + + postBatchData( + completeBatch.getBeginBatchMessage().getSignerId(), + completeBatch.getBeginBatchMessage().getBatchId(), + completeBatch.getBatchDataList(), + 0, + new PostBatchDataCallback(completeBatch,callback)); + } + + @Override + public void handleFailure(Throwable t) { + callback.handleFailure(t); + } + } + @Override public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { - return null; + + beginBatch( + completeBatch.getBeginBatchMessage(), + new BeginBatchCallback(completeBatch, callback) + ); + + batchDigest.update(completeBatch); + + return batchDigest.digestAsMessageID(); + } @Override - public void beginBatch(byte[] signerId, int batchId, List tagList, ClientCallback callback) { + public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback callback) { + + // Create worker with redundancy 1 and MAX_RETRIES retries + SingleServerBeginBatchWorker worker = + new SingleServerBeginBatchWorker(meerkatDBs.get(0), beginBatchMessage, MAX_RETRIES); + + // Submit worker and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); + + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback) { + + BatchMessage.Builder builder = BatchMessage.newBuilder() + .setSignerId(signerId) + .setBatchId(batchId); + + // Iterate through data list + + for (BatchData data : batchDataList) { + builder.setSerialNum(startPosition).setData(data); + + // Create worker with redundancy 1 and MAX_RETRIES retries + SingleServerPostBatchWorker worker = + new SingleServerPostBatchWorker(meerkatDBs.get(0), builder.build(), MAX_RETRIES); + + // Create worker with redundancy 1 and MAX_RETRIES retries + scheduleWorker(worker, new RetryCallback(worker, callback)); + + // Increment position in batch + startPosition++; + } + + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback) { + + postBatchData(signerId, batchId, batchDataList, 0, callback); } @@ -173,15 +281,26 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void postBatchData(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback) { + postBatchData(ByteString.copyFrom(signerId), batchId, batchDataList, startPosition, callback); + } @Override public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + postBatchData(signerId, batchId, batchDataList, 0, callback); + } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + + // Create worker with redundancy 1 and MAX_RETRIES retries + SingleServerCloseBatchWorker worker = + new SingleServerCloseBatchWorker(meerkatDBs.get(0), closeBatchMessage, MAX_RETRIES); + + // Submit worker and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); } @@ -208,7 +327,13 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback) { + + // Create job with no retries + SingleServerReadBatchWorker worker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchSpecificationMessage, 1); + + // Submit job and create callback + scheduleWorker(worker, new RetryCallback(worker, callback)); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index ce7a01e..78d5dba 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -2,9 +2,7 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; -import meerkat.bulletinboard.workers.MultiServerGetRedundancyWorker; -import meerkat.bulletinboard.workers.MultiServerPostMessageWorker; -import meerkat.bulletinboard.workers.MultiServerReadMessagesWorker; +import meerkat.bulletinboard.workers.multiserver.*; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.*; @@ -31,6 +29,8 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple // Per-server clients List clients; + 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; @@ -51,6 +51,8 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple super.init(clientParams); + batchDigest = new GenericBatchDigest(digest); + minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * clientParams.getBulletinBoardAddressCount()); executorService = Executors.newFixedThreadPool(JOBS_THREAD_NUM); @@ -84,42 +86,88 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple executorService.submit(worker); // Calculate the correct message ID and return it - digest.reset(); - digest.update(msg.getMsg()); - return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); + batchDigest.reset(); + batchDigest.update(msg.getMsg()); + return batchDigest.digestAsMessageID(); } @Override public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { - return null; // TODO: write this + // 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(byte[] signerId, int batchId, List tagList, ClientCallback callback) { - // TODO: write this + public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback 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 batchDataList, - int startPosition, ClientCallback callback) { + int startPosition, ClientCallback callback) { - // TODO: write this + 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 batchDataList, ClientCallback callback) { - postBatchData(signerId, batchId, batchDataList, 0, callback); // Write batch from beginning + postBatchData(signerId, batchId, batchDataList, 0, callback); } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { - // TODO: write this + public void postBatchData(ByteString signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback) { + + postBatchData(signerId.toByteArray(), batchId, batchDataList, startPosition, callback); + + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback) { + + postBatchData(signerId, batchId, batchDataList, 0, callback); + + } + + @Override + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + + // Create job + MultiServerCloseBatchWorker worker = + new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, closeBatchMessage, POST_MESSAGE_RETRY_NUM, callback); + + // Submit job + executorService.submit(worker); + } /** @@ -158,8 +206,15 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(byte[] signerId, int batchId, ClientCallback callback) { - // TODO: Implement + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback) { + + // Create job + MultiServerReadBatchWorker worker = + new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, batchSpecificationMessage, READ_MESSAGES_RETRY_NUM, callback); + + // Submit job + executorService.submit(worker); + } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java deleted file mode 100644 index cfc34e7..0000000 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostBatchWorker.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.bulletinboard.workers; - -/** - * Created by Arbel Deutsch Peled on 27-Dec-15. - */ -public class MultiServerPostBatchWorker { -} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java new file mode 100644 index 0000000..dc496d7 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java @@ -0,0 +1,28 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerBeginBatchWorker extends MultiServerGenericPostWorker { + + public MultiServerBeginBatchWorker(List clients, + int minServers, BeginBatchMessage payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doPost(SingleServerBulletinBoardClient client, BeginBatchMessage payload) { + client.beginBatch(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java new file mode 100644 index 0000000..56b09c5 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java @@ -0,0 +1,28 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.CloseBatchMessage; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerCloseBatchWorker extends MultiServerGenericPostWorker { + + public MultiServerCloseBatchWorker(List clients, + int minServers, CloseBatchMessage payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doPost(SingleServerBulletinBoardClient client, CloseBatchMessage payload) { + client.closeBatch(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java similarity index 82% rename from bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java rename to bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java index dcdc82a..8b62d4e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerPostMessageWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java @@ -1,10 +1,9 @@ -package meerkat.bulletinboard.workers; +package meerkat.bulletinboard.workers.multiserver; import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.*; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; @@ -14,16 +13,18 @@ import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerPostMessageWorker extends MultiServerWorker { +public abstract class MultiServerGenericPostWorker extends MultiServerWorker { - public MultiServerPostMessageWorker(List clients, - int minServers, BulletinBoardMessage payload, int maxRetry, + public MultiServerGenericPostWorker(List clients, + int minServers, T payload, int maxRetry, ClientCallback clientCallback) { super(clients, minServers, payload, maxRetry, clientCallback); } + protected abstract void doPost(SingleServerBulletinBoardClient client, T payload); + /** * This method carries out the actual communication with the servers via HTTP Post * It accesses the servers one by one and tries to post the payload to each in turn @@ -48,7 +49,7 @@ public class MultiServerPostMessageWorker extends MultiServerWorker>{ +public abstract class MultiServerGenericReadWorker extends MultiServerWorker{ - private Iterator clientIterator; + protected Iterator clientIterator; - public MultiServerReadMessagesWorker(List clients, - int minServers, MessageFilterList payload, int maxRetry, - ClientCallback> clientCallback) { + public MultiServerGenericReadWorker(List clients, + int minServers, IN payload, int maxRetry, + ClientCallback clientCallback) { super(clients, true, minServers, payload, maxRetry, clientCallback); // Shuffle clients on creation to balance load @@ -27,6 +26,8 @@ public class MultiServerReadMessagesWorker extends MultiServerWorker msg) { + public void handleCallback(OUT msg) { succeed(msg); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java similarity index 97% rename from bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java rename to bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java index 4d5e7f2..5675cb8 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/MultiServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java @@ -1,4 +1,4 @@ -package meerkat.bulletinboard.workers; +package meerkat.bulletinboard.workers.multiserver; import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; import meerkat.bulletinboard.MultiServerWorker; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java new file mode 100644 index 0000000..df21f9f --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java @@ -0,0 +1,28 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.bulletinboard.BatchDataContainer; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerPostBatchDataWorker extends MultiServerGenericPostWorker { + + public MultiServerPostBatchDataWorker(List clients, + int minServers, BatchDataContainer payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doPost(SingleServerBulletinBoardClient client, BatchDataContainer payload) { + client.postBatchData(payload.signerId, payload.batchId, payload.batchDataList, payload.startPosition, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java new file mode 100644 index 0000000..7c2f586 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java @@ -0,0 +1,28 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.CompleteBatch; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker { + + public MultiServerPostBatchWorker(List clients, + int minServers, CompleteBatch payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doPost(SingleServerBulletinBoardClient client, CompleteBatch payload) { + client.postBatch(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java new file mode 100644 index 0000000..33f9a3c --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java @@ -0,0 +1,28 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerPostMessageWorker extends MultiServerGenericPostWorker { + + public MultiServerPostMessageWorker(List clients, + int minServers, BulletinBoardMessage payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doPost(SingleServerBulletinBoardClient client, BulletinBoardMessage payload) { + client.postMessage(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java new file mode 100644 index 0000000..737c15c --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java @@ -0,0 +1,30 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.CompleteBatch; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.BatchSpecificationMessage; + +import java.util.List; + + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { + + public MultiServerReadBatchWorker(List clients, + int minServers, BatchSpecificationMessage payload, int maxRetry, + ClientCallback clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doRead(BatchSpecificationMessage payload, SingleServerBulletinBoardClient client) { + client.readBatch(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java new file mode 100644 index 0000000..b276eab --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java @@ -0,0 +1,29 @@ +package meerkat.bulletinboard.workers.multiserver; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerReadMessagesWorker extends MultiServerGenericReadWorker>{ + + public MultiServerReadMessagesWorker(List clients, + int minServers, MessageFilterList payload, int maxRetry, + ClientCallback> clientCallback) { + + super(clients, minServers, payload, maxRetry, clientCallback); + + } + + @Override + protected void doRead(MessageFilterList payload, SingleServerBulletinBoardClient client) { + client.readMessages(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerBeginBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerBeginBatchWorker.java new file mode 100644 index 0000000..0c1a1a3 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerBeginBatchWorker.java @@ -0,0 +1,17 @@ +package meerkat.bulletinboard.workers.singleserver; + +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; + +import static meerkat.bulletinboard.BulletinBoardConstants.BEGIN_BATCH_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + * Tries to contact server once and perform a post operation + */ +public class SingleServerBeginBatchWorker extends SingleServerGenericPostWorker { + + public SingleServerBeginBatchWorker(String serverAddress, BeginBatchMessage payload, int maxRetry) { + super(serverAddress, BEGIN_BATCH_PATH, payload, maxRetry); + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java new file mode 100644 index 0000000..ab298a5 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java @@ -0,0 +1,17 @@ +package meerkat.bulletinboard.workers.singleserver; + +import meerkat.protobuf.BulletinBoardAPI.CloseBatchMessage; + +import static meerkat.bulletinboard.BulletinBoardConstants.CLOSE_BATCH_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + * Tries to contact server once and perform a close batch operation + */ +public class SingleServerCloseBatchWorker extends SingleServerGenericPostWorker { + + public SingleServerCloseBatchWorker(String serverAddress, CloseBatchMessage payload, int maxRetry) { + super(serverAddress, CLOSE_BATCH_PATH, payload, maxRetry); + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java similarity index 76% rename from bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java rename to bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java index ee9fd3f..c56af05 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerPostMessageWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java @@ -1,9 +1,8 @@ -package meerkat.bulletinboard.workers; +package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.BoolMsg; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; import meerkat.rest.Constants; import javax.ws.rs.ProcessingException; @@ -13,16 +12,18 @@ 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.POST_MESSAGE_PATH; /** * Created by Arbel Deutsch Peled on 27-Dec-15. * Tries to contact server once and perform a post operation */ -public class SingleServerPostMessageWorker extends SingleServerWorker { +public class SingleServerGenericPostWorker extends SingleServerWorker { - public SingleServerPostMessageWorker(String serverAddress, BulletinBoardMessage payload, int maxRetry) { + private String subPath; + + public SingleServerGenericPostWorker(String serverAddress, String subPath, T payload, int maxRetry) { super(serverAddress, payload, maxRetry); + this.subPath = subPath; } /** @@ -30,13 +31,13 @@ public class SingleServerPostMessageWorker extends SingleServerWorker { + + public SingleServerPostBatchWorker(String serverAddress, BatchMessage payload, int maxRetry) { + super(serverAddress, POST_BATCH_PATH, payload, maxRetry); + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerPostMessageWorker.java new file mode 100644 index 0000000..454d720 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerPostMessageWorker.java @@ -0,0 +1,17 @@ +package meerkat.bulletinboard.workers.singleserver; + +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; + +import static meerkat.bulletinboard.BulletinBoardConstants.POST_MESSAGE_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + * Tries to contact server once and perform a post operation + */ +public class SingleServerPostMessageWorker extends SingleServerGenericPostWorker { + + public SingleServerPostMessageWorker(String serverAddress, BulletinBoardMessage payload, int maxRetry) { + super(serverAddress, POST_MESSAGE_PATH, payload, maxRetry); + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java new file mode 100644 index 0000000..61556fc --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java @@ -0,0 +1,119 @@ +package meerkat.bulletinboard.workers.singleserver; + +import meerkat.bulletinboard.CompleteBatch; +import meerkat.bulletinboard.SingleServerWorker; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; +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.GenericType; +import javax.ws.rs.core.Response; +import java.util.List; + +import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; +import static meerkat.bulletinboard.BulletinBoardConstants.READ_MESSAGES_PATH; +import static meerkat.bulletinboard.BulletinBoardConstants.READ_BATCH_PATH; + +import static meerkat.bulletinboard.BulletinBoardConstants.BATCH_ID_TAG_PREFIX; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class SingleServerReadBatchWorker extends SingleServerWorker { + + public SingleServerReadBatchWorker(String serverAddress, BatchSpecificationMessage payload, int maxRetry) { + super(serverAddress, payload, maxRetry); + } + + /** + * This method carries out the actual communication with the server via HTTP Post + * Upon successful retrieval from the server the method returns the received values + * @return the complete batch as read from the server + * @throws CommunicationException if the server's response is invalid + */ + public CompleteBatch call() throws CommunicationException{ + + CompleteBatch completeBatch = new CompleteBatch(); + + Client client = clientLocal.get(); + + WebTarget webTarget; + Response response; + + // Set filters for the batch message metadata retrieval + + MessageFilterList messageFilterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BATCH_ID_TAG_PREFIX + String.valueOf(payload.getBatchId())) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(payload.getSignerId()) + .build()) + .build(); + + // Send request to Server + + webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH); + response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post( + Entity.entity(messageFilterList, Constants.MEDIATYPE_PROTOBUF)); + + // Retrieve answer + + try { + + // If a BulletinBoardMessageList is returned: the read was successful + BulletinBoardMessage metadata = response.readEntity(BulletinBoardMessageList.class).getMessage(0); + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .setSignerId(payload.getSignerId()) + .setBatchId(payload.getBatchId()) + .addAllTag(metadata.getMsg().getTagList()) + .build()); + + completeBatch.setSignature(metadata.getSig(0)); + + } catch (ProcessingException | IllegalStateException e) { + + // Read failed + throw new CommunicationException("Could not contact the server"); + + } + finally { + response.close(); + } + + // Get the batch data + + webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_BATCH_PATH); + response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post( + Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF)); + + // Retrieve answer + + try { + + // If a List of BatchData is returned: the read was successful + + completeBatch.appendBatchData(response.readEntity(new GenericType>(){})); + + } catch (ProcessingException | IllegalStateException e) { + + // Read failed + throw new CommunicationException("Could not contact the server"); + + } + finally { + response.close(); + } + + return completeBatch; + + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java similarity index 97% rename from bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java rename to bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java index f8975cb..6c09bcc 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/SingleServerReadMessagesWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java @@ -1,4 +1,4 @@ -package meerkat.bulletinboard.workers; +package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index cab9d6d..fe3d2fc 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -141,6 +141,10 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } + @Path(READ_BATCH_PATH) + @POST + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) @Override public List readBatch(BatchSpecificationMessage message) { try { diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 00bd2ac..7732fcb 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -1,7 +1,7 @@ package meerkat.bulletinboard; +import com.google.protobuf.ByteString; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Crypto.Signature; import java.util.List; @@ -37,36 +37,47 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { /** * This message informs the server about the existence of a new batch message and supplies it with the tags associated with it - * @param signerId is the canonical form for the ID of the sender of this batch - * @param batchId is a unique (per signer) ID for this batch - * @param tagList is a list of tags that belong to the batch message + * @param beginBatchMessage contains the data required to begin the batch + * @param callback is a callback function class for handling results of the operation */ - public void beginBatch(byte[] signerId, int batchId, List tagList, ClientCallback callback); + public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback callback); /** * This method posts batch data into an (assumed to be open) batch * It does not close the batch * @param signerId is the canonical form for the ID of the sender of this batch * @param batchId is a unique (per signer) ID for this batch - * @param batchDataList is the (canonically ordered) list of data comprising the entire batch message (not just the portion to be written) + * @param batchDataList is the (canonically ordered) list of data comprising the portion of the batch to be posted * @param startPosition is the location (in the batch) of the first entry in batchDataList * (optionally used to continue interrupted post operations) + * The first position in the batch is position 0 * @param callback is a callback function class for handling results of the operation */ public void postBatchData(byte[] signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback); + int startPosition, ClientCallback callback); /** - * Overloading of the postBatchData method in which startPosition is set to the default value 0 + * Overloading of the postBatchData method which starts at the first position in the batch */ public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + /** + * Overloading of the postBatchData method which uses ByteString + */ + public void postBatchData(ByteString signerId, int batchId, List batchDataList, + int startPosition, ClientCallback callback); + + /** + * Overloading of the postBatchData method which uses ByteString and starts at the first position in the batch + */ + public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback); + /** * Attempts to close a batch message * @param closeBatchMessage contains the data required to close the batch * @param callback is a callback function class for handling results of the operation */ - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback); + public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback); /** * Check how "safe" a given message is in an asynchronous manner @@ -88,11 +99,10 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { /** * Read a given batch message from the bulletin board - * @param signerId is the ID of the signer (sender) of the batch message - * @param batchId is the unique (per signer) ID of the batch + * @param batchSpecificationMessage contains the data required to specify a single batch instance * @param callback is a callback class for handling the result of the operation */ - public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback); /** * Subscribes to a notifier that will return any new messages on the server that match the given filters diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java index 0db1d3f..6bfc06f 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -9,6 +9,7 @@ public interface BulletinBoardConstants { public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; public static final String READ_MESSAGES_PATH = "/readmessages"; + public static final String READ_BATCH_PATH = "/readbatch"; public static final String POST_MESSAGE_PATH = "/postmessage"; public static final String BEGIN_BATCH_PATH = "/beginbatch"; public static final String POST_BATCH_PATH = "/postbatch"; @@ -17,6 +18,6 @@ public interface BulletinBoardConstants { // Other Constants public static final String BATCH_TAG = "@BATCH"; - public static final String BATCH_ID_TAG_PREFIX = "#"; + public static final String BATCH_ID_TAG_PREFIX = "BATCHID#"; } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java index 8171271..4f25f59 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java @@ -2,7 +2,7 @@ package meerkat.bulletinboard; import com.google.protobuf.Message; import meerkat.crypto.Digest; -import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import meerkat.protobuf.BulletinBoardAPI.MessageID; import meerkat.protobuf.BulletinBoardAPI.BatchData; import java.util.List; @@ -36,6 +36,11 @@ public class GenericBatchDigest implements BatchDigest{ return digest.digest(); } + @Override + public MessageID digestAsMessageID() { + return digest.digestAsMessageID(); + } + @Override public void update(Message msg) { digest.update(msg); diff --git a/meerkat-common/src/main/java/meerkat/crypto/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java index c72206e..b7d86dc 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -1,6 +1,7 @@ package meerkat.crypto; import com.google.protobuf.Message; +import meerkat.protobuf.BulletinBoardAPI.MessageID; import java.security.MessageDigest; @@ -15,6 +16,12 @@ public interface Digest { */ public byte[] digest(); + /** + * Completes the hash computation and returns a MessageID Protobuf as output + * @return + */ + public MessageID digestAsMessageID(); + /** * Updates the digest using the specified message (in serialized wire form) * diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index 4aac501..a7723ec 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -3,6 +3,7 @@ package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.MessageID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,6 +61,11 @@ public class SHA256Digest implements Digest { return hash.digest(); } + @Override + public MessageID digestAsMessageID() { + return MessageID.newBuilder().setID(ByteString.copyFrom(digest())).build(); + } + @Override public void update(Message msg) { From 6100497e8e0f5f55a88197022ace85ac2ca75488 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Wed, 27 Jan 2016 13:41:24 +0200 Subject: [PATCH 009/106] Feldman's VSS --- destributed-key-generation/build.gradle | 220 ++++++++++++++++++ .../VerifiableSecretSharing.java | 54 +++++ .../java/ShamirSecretSharing/Polynomial.java | 119 ++++++++++ .../ShamirSecretSharing/SecretSharing.java | 56 +++++ gradle/wrapper/gradle-wrapper.jar | Bin 52271 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- gradlew | 10 +- .../crypto/concrete/ECElGamalEncryption.java | 2 +- settings.gradle | 1 + 9 files changed, 456 insertions(+), 11 deletions(-) create mode 100644 destributed-key-generation/build.gradle create mode 100644 destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java create mode 100644 destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java create mode 100644 destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java diff --git a/destributed-key-generation/build.gradle b/destributed-key-generation/build.gradle new file mode 100644 index 0000000..60ec7c9 --- /dev/null +++ b/destributed-key-generation/build.gradle @@ -0,0 +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 + } + } + } +} + + + diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java new file mode 100644 index 0000000..fea7a1b --- /dev/null +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -0,0 +1,54 @@ +package FeldmanVerifiableSecretSharing; + +import ShamirSecretSharing.SecretSharing; +import org.bouncycastle.util.Arrays; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class VerifiableSecretSharing extends SecretSharing { + + private final BigInteger[] commitments; + private final BigInteger g; + + public VerifiableSecretSharing(Zpstar zpstar, int t, int n, BigInteger s, Random random) { + super(zpstar, t, n, s, random); + this.g = BigInteger.ONE; //ToDO zpstar.getGenerator() + this.commitments = generateCommitments(); + } + + private BigInteger[] generateCommitments() { + BigInteger[] coefficients = polynomial.getCoefficients(); + BigInteger[] commitments = new BigInteger[coefficients.length]; + for (int i = 0 ; i < commitments.length;i++){ + commitments[i] = zpstar.multiply(g,coefficients[i]); + } + return commitments; + } + + public BigInteger verify(int i) throws Exception { + if(i < 1 || i > n){ + throw new Exception(); + } + BigInteger v = BigInteger.ONE; + int power = 1; + for (int j = 0 ; j < commitments.length ; j ++){ + v.multiply(commitments[i].pow(power)); + power *=i; + } + return zpstar.add(BigInteger.ONE,v); + } + + + public BigInteger getG() { + return g; + } + + public BigInteger[] getCommitments() { + return Arrays.clone(commitments); + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java new file mode 100644 index 0000000..69b4da5 --- /dev/null +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -0,0 +1,119 @@ +package ShamirSecretSharing; + +import org.bouncycastle.util.Arrays; +import org.factcenter.qilin.primitives.concrete.ECGroup; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class Polynomial { + + private static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); + private static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); + private final int degree; + private final BigInteger[] coefficients; + + public Polynomial(BigInteger[] coefficients) { + this.degree = coefficients.length - 1; + this.coefficients = coefficients; + } + + public Polynomial(Polynomial polynomial) { + this.degree = polynomial.getDegree(); + this.coefficients = polynomial.getCoefficients(); + } + + public BigInteger image(BigInteger x){ + BigInteger result = BigInteger.ZERO; + BigInteger power = BigInteger.ONE; + for(int i = 0 ; i <= degree ; i++){ + result.add(coefficients[i].multiply(power)); + power.multiply(x); + } + return result; + } + + public static Polynomial interpolation(Point[] points){ + Polynomial[] factors = new Polynomial[points.length]; + for (int i = 0 ; i < factors.length ; i++){ + factors[i] = new Polynomial(new BigInteger[]{BigInteger.ONE,points[i].x}); // X - Xi + } + Polynomial result = ZERO; + BigInteger constant; + Polynomial product; + for (int i = 0 ; i < points.length; i++){ + constant = points[i].y; + product = ONE; + for (int j = 0 ; j < points.length; j ++){ + if(i != j ) { + constant = constant.divide(points[i].x.subtract(points[j].x)); + product = product.mul(factors[j]); + } + } + result.add(product.mul(constant)); + } + return result; + } + + 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] = smaller.coefficients[i].add(bigger.coefficients[i]); + } + return new Polynomial(coefficients); + } + + public Polynomial mul(BigInteger constant){ + + BigInteger[] coefficients = this.getCoefficients(); + + for (int i = 0; i <= this.degree ; i++){ + coefficients[i] = constant.multiply(coefficients[i]); + } + return new Polynomial(coefficients); + } + + public Polynomial mul(Polynomial other){ + + BigInteger[] coefficients = new BigInteger[this.degree + other.degree + 1]; + java.util.Arrays.fill(coefficients,BigInteger.ZERO); + + for (int i = 0; i <= this.degree ; i++){ + for (int j = 0; j <= other.degree; j++){ + coefficients[i+j] = coefficients[i+j].add(this.coefficients[i].multiply(other.coefficients[j])); + } + } + return new Polynomial(coefficients); + } + + + public BigInteger[] getCoefficients() { + return Arrays.clone(coefficients); + } + public int getDegree() { + return degree; + } + + + public static class Point{ + public final BigInteger x; + public final BigInteger y; + + public Point(BigInteger x, BigInteger y) { + this.x = x; + this.y = y; + } + } + +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java new file mode 100644 index 0000000..4457f95 --- /dev/null +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -0,0 +1,56 @@ +package ShamirSecretSharing; + + +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class SecretSharing { + protected final Zpstar zpstar; + protected final int t; + protected final int n; + protected final Polynomial polynomial; + + public SecretSharing(Zpstar zpstar, int t, int n, BigInteger s, Random random) { + this.zpstar = zpstar; + this.t = t; + this.n = n; + this.polynomial = generateRandomPolynomial(s,random); + } + + private Polynomial generateRandomPolynomial(BigInteger s, Random random) { + BigInteger[] coefficients = new BigInteger[t + 1]; + coefficients[0] = s; + for (int i = 1 ; i <= t; i++ ){ + coefficients[i] = zpstar.sample(random); + } + return new Polynomial(coefficients); + } + + //ToDo make it safe : permission to call this func + modulo calc + public Polynomial.Point getShare(int i) throws Exception { + if(i < 1 || i > n){ + throw new Exception(); + } + return new Polynomial.Point(BigInteger.valueOf(i), polynomial.image(BigInteger.valueOf(i))); + } + + public static BigInteger getSecrete(Polynomial.Point[] shares){ + Polynomial polynomial = Polynomial.interpolation(shares); + return polynomial.image(BigInteger.ZERO); + } + + public int getThreshold() { + return t; + } + + public int getN() { + return n; + } + + +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 30d399d8d2bf522ff5de94bf434a7cc43a9a74b5..941144813d241db74e1bf25b6804c679fbe7f0a3 100644 GIT binary patch delta 12486 zcmZX41yq|svvzPP?(QyyLXo1SxVyW%yN2RLiUfCeDDLj=?ox`o7wJ!F@BRMXFX!a! zoacRJc6N6%nQZ1;B1AwA1d^O21SC8F01FFn_-HR0jYJ9id+a_H!Hwot!&JX;IClU8 z{D)-nn^Z^w`8tkJ{~2$YUPlle*v6|+jRfuh{s#(x{P72}fy(&!w&lv^mC9Xc4uj-gJ}PXIYkXFNnq zgh?G;o44QC4w^MbfBrZriQsTX^dDeFNcACorax!Hh?y=*E?E z>28S}PAt7)273+$D1@AU!RWm^&SHYq#b~4O`fvrImzr_JoaRC^J`j1x-*KgI1Zm$I z%PGJTuBe~-j5WjrA{2?Sf`SWmh^5tw&3+dyrxFG&ZxYVajj4s1fb-p*u?Q&o<8ZMe z79}+dWV&Uqg}w!(JotKUi9N270vwCL zHs*_zD}vXG4Eu}uaZ6JoDi?tz2ePpYT6~DaF*oTHLIH&YBoS4LP?ZVUm;*gHL=q`} znTsqY?<++spujTVNGYa_7!xB9FJ3(blS}c@LL#aLL4jP=Z_naIsFF#Z_x?BpZp1aS z^7Q844?y)C3KP_yu!h5m{2SJ(ILa_czr&hyt!@<`9RN6@1^ptX0lx9V*s0~GZeCnu z=%z>M8nP53a}VagLqQaeT0n_9VH0n|1LTf-VHwkZp zEFCM8yFo2^A07tceVpmQV-o!M#pMxTTwi)~8o~*09Ptd7N7h3k_k-f*Jy>%0HiXuY zF<9}o!+mK~zCv=bz1AojJk#0br$Fq%@LsUwamid@QAWa`Bd{^VGd?_xFw>y?`V!u~ zoMFS!P1$#R=MvnlMA6OJH{Kt+?;y`SDqo(a6cv8=!M*J2J+0U0u8a%E>Wq1DQAyvi z?dvHk*t5VE`OP^%+0MDo8pZhNloFKN8(ZZ&vcP4dsX9Q}?lG9fW*FugYNpEOa#zCL zy~2HiR5D%QH4sp1-`tf2u-J!wVI=CApcNX_88f$!ve2p5LmWh6d z5taw+9JWn0Sw+s%efhH~9BgH_jZT8A`L$AkqX~!2SHR>DqQg@2S~QbVN2uw$pKc81 z`|m8nh{OdhER(#V-AoIj^^zwEWS!=msIKgK3irkLR#!!`^B0MFB!HZ2=wUtA%+pr& zU!)QD?Kh{&G_{=vb5X4$VRssB-mrfk>&%`GUz4MVd+&;CIT9j|4Uaqcor^brxoWmS z-i&7xJPLSO_TDhRHgrE`Dsu90o9#p6g0W^|%k_Ch=ljaVa9qYBv*zf9Tthh?6y*JA zMvt!8Q>TLY0~U}JtM-R5TQXEJVpvLqRTjLF++L@;5@^jdYJw$wmwdD)<32$0V@fVVxta1fN9ZP=5^WsRWK!q^7w>@G#fvSKaEhT01vM`FVexM*rG=BI zM1`({QUwCP3A$bm*ihBdVnLjSAmwy1OUhVWx#xs@L=lEGXGT}Y4VKDWs$vDEl7P?J%`9x&4WF+-y;D9o zvonQWGM_~8>850V%oPS(2FwFqeu=lm?92umz;Ga<4^ zw+Z-xl!J;MkHWOol7|dF5t#RC63v9ji1r6y>N1^r^KdjTVfeMSh?%K^S9Oh3O%3%d zw0*G>hd(ypc@@3it4DK0lySf@DzN7>hSK!PW>iVBsw~A1Qj@yK zniLL$9_A?1Y+5rmZo{TH37i~l=9v62@qB8;l1l8%s-95%aG@C~DyV^w(&(8w*kL0e z7WtlQg?<1Bp2vcCv^YJ1thzeMQt5mTy8LR@5!@QA0^XieJvr|#jWRF zimb`lNpzzgoS@6=#SP79sL!q0w9xTilsLjOxG6U%{A$l>_QGBH4z?!?i3DSd)KFzh zhdpMcY}gDJ@-u4-YOL@v!l^Z#)YVad>|{Z?(*a?5%<|&-N5>EsTf@W$eg<$56X{i} zY-in{X!tRkrvkPdwG3(JQSU`YB(99T^_OuaEu%nq#zHX|1ks~lXq>oYhmJo3Ye%Q> z*^Lb40?KLCt2u)m3>h%ls>HP#SwMH8qK>kHP6jk^AOJ$D$BISLN zHlpx;CA*>Q@#2~k8@YXtpQT;R%59%*mF}t5a?WrR}FdIvqQR^1f<$Qp?U~xE-SbBw`X4fRqtiuZqKy` z-kuoyce$24vOPBq-Jbcxo$lC*Ic5yqhM^%BK9W2k;CD`JMHD3(i$qv;nKT`FX;L%R zt4#bzpxCwCY>1vQu$L4Ru-G?|nl|)KjPLNlPase!W6S5z9SyZ46#Je$8RpG3Rlqnh zc32{k^sWc!{jjsAa-ZS_{D^Q9HMG9c%s9&^olZAhX$Q^O;Jh21%2};4wdBp8 zRn|tUmb?;Ds%~<66OlFQ%Gj}Mx%!0@OT!zFVU@atph7vXQzeZE7`&7`QDjsr+7a(PK>fwM+Q-uG1R=VH$SMVScP6ZzK11A9uz7U zlzLLyE4Y7AKIeilVCL)+!EW(!M-(a|vdAlhSoIDrE(4>V_=nHYoM2M*+vtf03h!c` zkNk@Fu>5%!(--Wpz>LWhzwaNLaV250I(BibCa8<;gF4?T`s@ZbW!uk?rte556hAVY zqSA>f^Yx9>K5ECcQ|mDh5n7suYLw`M=_fhJ91<1p)_ir#RsrpK>TF^wJ@fI$ep!+a zBv70%E^+Bo@`=_(E7FPo5vPwegylikKIAE<7{X5xuQM!#57enBdW1+~f7rHU&%gNT zMu%1>$m@;90?l^~%qAncJ$5GJR7y zL+|5&h{Tt+kU(x$Q7*%$il5dVHWFimX#6eoHtw={{F9>azf^YC&#&p)$6d+l)7>;b z-lyzGM~RNsn;pUIgqvF5?%W~lRK*tMNlRa(0z*|HX$b6x2xNc?=8FT|e*5H9I|S7Q z@l8afwIK68r+u{(A->6oPn)on$K8S|tyu=|eccy_1A(g<4HvjJwTdcZtrVC0``c1! zhl@QT>^EI<@VNXYvonI6UncbD3C4cFLz#MwXhV;U$gR&YVfj73(H{F@Ox=i(v=!49 z_4N$)4ORWOx0Ze)MJE+D;`jbYF!^nE8j!Z;Nm?;dMCnOKp568;UdI#O;_~Jo`ZX`k zN+%6%7XlzGQ)M*)vuW&HWO_!cK@m@7xy|&G3J-aIz$PYNEDI=N(&mk*kZy2V{ITN* z&B3y0bH8#18OPxFd=_&ZICPJVD*3*Fre#yD&lsr$0+ih{GP7g)OJAOwZj5+hst~>u zY^E3y(?Q%#`ZJQp5Z zlQzuBx)?>fK;lOf#5&G-ABU|bTp z9_q_Y!K%}FFmjYQ8(gV`ly!56BX`x(GY&S8LBQNKD%n&GpI#lm&7O_T%DR${zWPZ? zka7$>%#1Vq^rKLcaxh_$8-I`pe=3h|I;p@Y1`{{+0~ke-=G!9ndXrzf(X16+V_>7_ zL=-X@c!E3*yA2m|asoK5huktKGSWBKYE$;@hm7(S@8==AZH+^xi37=L-HlRgLGF zGa-%Jd8#VkN2nct3^RHHjwBr-l56G&rf-~567DFJB13kx&yc}068BciGi zxZ?dCD2>Xpag`7Uu@@Z5og0jIw1jnYflLC~UR)_{Ql0{oA0_wL7v}wIcbvFa;YLk9 zj(a;{n~dfqIdQCcU9pwk80^efLhmYz65D*z1(0)K$nbyaboO`B(Ch__nw>LT%A^a8 z-&tOUwYWc+n4F~(*0=s)C>to?>@w+1mvrNk}%9vJp0 zus-=<)@j5=bcK13t?L*d^NkS}>uOr-wDtYlLMe?2SyL-Sx+yl>LmPf#&Swv~{el?M z>e8%1v-(d*VP<5tV0gha-PC8dzf%# z6t+Tl`PeyJ@lyw<$oFk#-W6g~f(WDq<4%R8kL0YP6ID0IG>o~A zrhd__I-TXEQXLU#X7d(~2z|7~O+j#p2$E-d_5qIs!~h5)lYWAV#1So18VtzST$t|R z=(`p(Thj{-y=)uVN#?HB7>_i$op}p6XpCOqnJy$-E)!hDUp8G`;cI7I>Jfb~Ob=6- zKc`7qsB4GK2u*@z!>Ek+2ht=mkC%10F&@XF~+gSR)@gXX|2 zoGzB}zH>C3JT~tkP;df`qvpEQqyw?9rVDx|-L4cJ`OCOJT0$4)Sx3#)4?ZG7IBf!~ zW2GiTp;9a`->v_s)A$vpM4$v;&nbueQ}e<6P~|(OI4pK8L8dvuzoM`{KR?wiwxlkh^E#WuIC0t<%vmq#76O$ zV2(P2krnT&4QJ9S-5#)jjzSbO!K>y-^#qTE5}jZ=TAS))okA~b^Dy1KCcHr*P~jTI zWz>G?6g5k^zZiREwYB3AMC!t27kQLpFqx~smpze}VeoMu-yZ{}r+GOj0&xNpBK9K~ z%9VsF%N{-nP;w)k>*F@zMuFc@B}Bh1c7Aj2v~4@oQ$LbG4x!TrJ%Ky*8&+Q}H}rIl zP6>{P1+w+7z2*0C9xz$=JbP+zjN@6iQSa7a^49(5h-qYg0VIGQZJx-@yaTuni3Rq_ zl~90VR9Wr|7VA0dU3J_Qqt8esl)a~;OZH6OQEQwxK)>P+8?=KQWPw=-+#BC+Vp314 z`a1nb*^Q0wbD9&>D6~mO!qSrp@_`!J)=9TE$#Uw(s%X40Uw`51?FnNPh+x?R1s-hW zZobhNKcnxgtdkr7jXwjj)lnrg=fE_3&}eSjTI)wEU9FJy6r_F`?M|15fF7^LGfzSm zLOu}j0OKy;t<0XY6nae2Q}tPAQfaT4%!A;cESIR@gF%#jlPdTZj0`38 ze3#L1rsB-4yyMS2-0N*q)O_T?8Bo_skpbsxezem)hHPXii5s7UcY02F?vMC-yMeR+ z$n>PUG=i^3D9+}ShUj2H?EAqOk1IRz z=~%PF3S23(V|vQFg|r*EZ~=D)p38+Wu8$WsM5~>`g>URit9B=ULHwVaHwmUUP_LKA zVsrHr(=Qj-*<|$zvshuM`V6@y;ih~ZAPCJ)DBI5n$9$z6-*&qBp`IwhK+h- ze`GzB-8W)e4am=~=t6U5K~{Myr?oIxF^SWg!_a93%pz_^`2&Kc7>*HMp6QWr!3ar=Avg5(1C>V!&13a?6hiA z*11#h@l`HngW=_R#_7K0V`h<}pPqln?GCVy{|Idv-K!g0#UJCbbakrH?Yz)#6>QES z_wVKnMC0X#+VY#ue^-{G@=2Cn?MGsICEDQEtQD@&ZyFm*$zoH_biu6pPOywfC(|Ps z-h?A+)4251Ln2v@9vVQ|-dg*VN*F&ndgqH!RT~yu9@n|E zatNU(H#UEDzZz zzt7oG=&K}8L}L6(RuWv+s_^I0+91*_=kks$@YEp=Y6ZAMFQ{E0W^FCXzM)%%;O9^J z&gsYLPw%{!g!@gUsc>5RdOtK-EzK0LDXzzev2ypbk{QiN(QszDr{$33X%gmix1yES zM87k9bFQ-h_X9!f;oPxreWtd7aSDeGG_uL#5hj!O@)LNQn+>|$&sW+!J}>1%ffYsF z7?Yxau$O?E^3=o@P%vG{S_325Pm?6t0QF!=Nd|rVDnBu2?1GBlr?XIYFCH7&uQRTN zL1|*@@sq;bx8*4GX2}#L-X=;6&bYDx+VeT#IX_2<7-!@JVbEFXrH8sg&S&t`}f4AyU0Fm5x}JY~fm!dF{-0ZFU!fJDX568O9qZ%-#i zYmO&bPA!103Wk_R;vssv+*$H*3OuaHB0jdNXLt6~p{EdG5tM{qci%=-q-WDPur-Qs z)CQ%%M=)wRGFro17P&o-`PE7vZ$^vrmIdEZ#tfb{5V2p=8Zu$#Ba+V&5lI{%cyfYV zq(L@AmSx_EidW{nyQ)Kwtqz#=@Xy1o*9VOTI5NQAZ**XJUEd&;^AzCEFqt1ii|Hg| z>Dm>_=%{HVF`bZb^qU(e2rOB=8htwCQ_|-Q4Qx`OF-B9}kJS9BJwPNLzH%qGx%$#4 z&;(bd=^jU}GhSgk!iq}_hK<@s<|!+2suxJ~A5w=~-Nvui6l5Z4*4hq3S8-WC^AX@@t;1;pM@wu~Kwg0E?DZ>s!E)D%cxic55vftuFo zTC@*n=0-yO@XW@}VvhIVAlnBY`lXM`xoDfxf%tMVp(=Hl;&x8ct#f{7AxEaI*UeX- zp&DUpsKMeUOi5rl+s3hea^T4v_p-6_9x4ymBX8TaWH4?BRp6fIB5Pq1i(QuKN}M5S0IxH%Bf`2@XKq{klg6gSV+V6Lmjo}xIg zeL(P=u$Ya@n4m-BvhLdHO~O21yK4&zIgmywK3L@tWIBtQxz8s52KRI^p*9)Ge##laaIZbH;l=t>}DQJCNCC%Pfmu2 zCtbX1yWo|Wk{@h*BM)ae32Qn1<@wR6HyO%P{b9!_Yf)PlggDu|d)ynqb`?da^R#?D z?MbWl>cDvXCsx9C8W0i`i3C2ODYC~_vloW)f)MB`O~GwxcfD{OVhj7+Wp41`)GUeR ztvtc6U4HQRCNnHGPIV#-ZPg?J;{)}AtgJPQp2!MooY>x;L)J{zW{2PNM$nrDiVyYM zCO@di+`4!oqAUnzU8`Gh`sF!trl~jkV403=jo@lHtLP&k%I~=3?}d~pI14qy1~~%kT|nAs!tgJ#}l|0 z-N-(dFd*I3WD8z<2kvDL1im?L4QOu@ghd*tk8s!glv6Ax+Q-#b`xZMO4pOm60BTl6 zUO!|}soxf26APl7eWt`gxOHfZf1k3}?L&E$w(Ce!GJo6g%5&9cT{z>8qO#{MnYi-+ z?v1A6i6qOFOTv?TmJhmacXZ>MRV$m8_Gw|_F(Q%)aJ5`ZFzi2LxNo%?=T%E^L59JXj00WZ`hGZt8Uywk6qmcQ8&h0Dkj#Or=Pg=8Y ziX@UXU0#%&Itw|orHgz5JTK9e7{yEyU!#;W7ctVMtbEqzNYn=km}yKLVKiK|MRl#g zce}>An_hkT;eqdJ{Fj#lQHRK*H*S-?T92!cmukETH6uVOk(zOlGc8DJayOkU@1Y8A zYYxkW92MZE%rHBqiV;;fExC20IqofO%@^r0x}Om71$OGz-_;E%*B#Oz(s?-s-#uM@ z_V!P$kr=5ezs!tdat~Udbu!js${6z$8DpOo<;{^}ZoLwlxS3CJ@X3BRa@H`}Y<_8H zu0TozS&c}YL6rX)v>TuTT%mKZk=rxFGM=FQ8DtF%TV)@vd?bXAq)uSbN(?Z`S<+zg zkPnl0B~+UDxk^yo#$x#4hn%^?$kh$Lp+c~m$dJRt83V3rTym)b82r!7ZDv1fj4&#; zd4|fwu?Vet5mN>w&#IEjws*iPX4NM-na~vjXF4q+9F_+cj|q-O_<8h8@osJdkI(lG z{qG%ty+KEe5ou-lgZQ^qSaM*F9fXgQc+u5p9g%H0&Ui4dtrd`Qb z>4nm5_LcG+WTr_~ZyG`-!}_kch=4`qs-x8X{kso3ljm<*hCHqtM4hCD8<4;4yAj&% zxheK&W_#kF(gb+I2kjo-IT%B8j6}i^>VNf4c`cKb135mCm zfn3ia)2Lp#+p>3#ki>_HsQku9yZX#}OZiMPV)#@u*I%bsaYsb#RQjnou{(909x->5 z8X?96RkBFxC_1>-^EM0ar22R7KJ~Bn?D#S?8PXDgq$Ajr)T)h8;T(L12+T3c+w2JZ zMm_R3Qy{*lcg5$!2v0M%nb`)$RP`t90;Pf9NGrg%ggA*5yh5R6h?Ru2^6~q|$$J+*O;bm27LAKkHAzAx~io z<1ytp%N^CafLk(psYEPB;gUw~N$@GfE|2E@-nS~S*zoBN_W2zt*FP#ON@`8u0u>FL zr4BGh5A5xT9KL;AbJ>rAvBa-B1?Sd#4vF~jqsbD4s5Q2saCP1g{ z?>+o0XqDOhJgdzhE2y&UAg>d|w>bOA@`Y*6!807cm-G@x+e{{}sIx^`&qWtrs{A}Z zY^4Qk73LtFz`1_sv0LOD@wnhJ1#se|9oFo6q%jdu<4uJ+_|?<8ZM=tSy|x414#JzS zJ*1a~g%w|s2Z{Iur_8Kv6PgkAmNl*2yOlL`9OB|{weog^2X>u8et9qSEiNxEhhYgV ztR-sjL&Pb@anopiAP)C}$ph-_uZP%X z6JKy{Nq?gEusui3r<~E;Md6M8iNk2jz#Y7h#cK9O!~=JDo1SJ!%{?d*(?Za=G`TPN z+PJ5nG8vw7XrtS>y5Z4@ne`cuY>Cz^>zHslQEloMrsH#P)36#Z8K0@W@hr0sCck1{ zTy&-~t}4uWJ89EN^&V^%w;iy~Bsa(eYaZczS|hMb;}iEAo#N?*x2=|#e1cAv4Wxa} z;nA>;U|_KpQ9^E5^O31PPYaaW-|sPOLx1V}HK(p(oRyLSUdZ@4$BhLi2=7US5XD4Q z`?;Y5Ke4?`gR+J_48yU-haxMjyy8}Y$U!LCyUGobx@;auI5=L- z89ul2Ir6M4Z6Kdp7_IMII`Ww5L5jvJULJ5{!6kqnD{@4I3&cHQc~4kK%54!_%Tj1q*W>%X<|&7evsJ1{0e4iHxR8zIRSGvSsD2X5}vTaVcO6k9C%cUbrK9%O_Vv z#h?MG3n~2g`QtU%19Qr!v+L=7d6x)9L1Yy_(9}@5^4JX^8?%_u)4b;+qRt{?9G*1E zv6&#B@wUkpt?WpG<9kW%#=PQhCU1LAOjy@r!(`>jRSA4PRw&6JUnWEzo+7P11Q~X3 zPJHPWims}+8r+wuJ1_+wzPZNLe6#Zld^TBIE82RTTvSo)4PVRoa0M&yKRfq(y&y6z zddS~GwY*j^_^Sk3(b@Y04d_1qfvSfL_WnwB#xY=jo=TY#!TynKY>6QLNKp=4f2A?! zDX2eKuIK$V7(F}UF))zAO zE9sy6+J8vCoUayTkbYm^;=Pjpx0wB1%l<=75_}~mbdbLi|5Mch0A&9VK{Btz(+>PU z+mF|Jt2@bIpG=Yd+8F zzGR+vB>$aS{(q8*-btM=c>Y#6AWz1w~WzO{fAL4IgQ3F@; zJTE7&_;T{^{$uOq~INxcFOvMb|ho|An~s@}~Jmfx-wR+fNQc)P(`@bR+!n zLaG}N9L4w*59_9Wb-$%ln&o$Mw*SkFy#E+LGkYb<^+AIky2<_+Anm~ef3|qR2|ydh z*dV)}zlMEZ@K~!?etQqiAMW7`R_FA;Hkf+}{@`-Gc;E}JuXtoH-5;#=1;g@uwR`7` z0J0nWYZtW-5B$jYuMP57hc(@75@TQDydU-d#`(S<=$khUsJZX2^6-mtXDDd5PwZ8Z z#Y(kK;$@|fFDw0>BmU=A^Eod3Wd@~JQea*Uwka9_(DxFK|9*-DBVR~lpq>6d*$nj1 zj|YB|1&SP|0r3yu{#l0B03P^O?q7GIL0JPhf0y@y_ZGYyATB63o8rF?5tP<~+4ABU z$%|(U|KrxnSo7JZ^kqq8pnvwncMuOe;M@OB(mVL~Yz|*=*Qyts0MwX`{9ls@PGbEy zfB*oz-T(kR|4cGp{c5bE93PZA^mp${hw#Ah8$g>?-2Y{W5!1{M=Ed9QmsG&=kD-%B z5YzC-*L@VJgT3W_nQiDLS8)GB5^j0fGx1l_|7PnK!oPWLxgC_%L<+(kL4nrk_^tl` E0L*8@(*OVf delta 11073 zcmZX41z1#J)ArKcxpYW(Nq2)F4Fb~LARR7^l*H00(%m85or_2}64E6h!jIthy}$3b z*R|I(XU=_}nP;9kvuB?(!MQM%DKO|NiZHOq001H)fJA9mCJvnj@z2-|-LMoVsDqb! z=5p!+1^6#e5e4iMc$DsWykdJA!HiIAPeLs^v*ti`>d+PL&S#1`olM^ z3}`lj1^_VO0RR?o94tOq8J!puzvwV6h8b!J=2Ir+9nWE5*%8b6sP_ZD381Q(@RB4? zOjSZJJbhR`YM*f~?$EziJwPhB7Y?ISlG0*UIh~m}9A#p3d|dS0>tGf1{vO(2KuAR_ zKo>oVKPBjr#7+eilcr?z%BI1rXv8Vof8kvZy^~))oJ$hMJC;I5--0{r{!YmLT zzfX*LtUC91F)#BEo_kVIeJmT}-ZW1_eRq9?p}p~vgEwiSibiYEgC3I&>2bs{mL*=9 zpQu3@wldj9dLDCzP~C6i$@=UT*GQ(%n)Yg}c*81PXl+)9N4&&zVTUsNTi?6(Ly^x_ zDA+|;cz%D)K_OpC!7Q2%hp&G+2|2O*QIg;*T#K@si&WQ3$v2b5tDNbzDh z?dwfWnSjX|v?4fhjq(b-PdkPApsE~AVV}T79jlXJUVRrmL@>p=P9bItPYuUvyl)<* zbpk~)PGsy36h1;_rIUPhaiPrFE_t-?Rm-eskcp|dv%!=S(JeDr$QuQBqQDD5KIV0mW?mkY z(HPUYV`DEmZ@l0Zc3Ply+l0_M5MxuP4yIhVOkcbLuQ*J93tucy0<|57-gTrd&nW1k zp2cLZ_?)j?wg2*5J*z(k-SAK?j1vUn7V?^1zXO8qB|;q&O|BJz_X;8p0&>RQ>N$=+ zA3AOlDH0(bTL&z_ds;b=B8VXG7_y46hjfboY%iP?g=dg@c=73>Y_cO^ssqx&aB&QE zixG0qCFgcwC|;8Hko5ZjY4TzC4ut$06#EjAE?)BKc*F??24_5_3oaRUj#|(l#1Huw zOc@B4kAgT~yyW{QRC94Huhj1E;x_rbFs&q9m6$1sHOO#Yc$HdB66-wBZ-9A%Ul`?l z_{&ZfDC$v8+k9pHXV-&fM=;eqC1VA=a=YUw+|K&}j>sq507oPjp4o&mtrhryrk9;= zoUphjF&tYAA9Xr`ghd#TnA#gYJs@lT3J;l$6i=#R9)4w|CLQ==#T8gj9((%X-=R zq~IhHdtem{HGgxA^_%3>SBtt3kpdb{Z-2p*JEV868jUGOyFBGnNvevGbQeiTii)6o z*V6o1{@yXMr3^XRS1jXoIfO=af zZ=tAjJWw(A_gu4+zLKoyMi}pY*@OFZ-bgIpvohh@{L_BR+ehAE%zc@I)-f44o0@b* zB;O{=C6cEn%R>?YH)_n{{Hhl9X50bfeaJyQR#!o9Uadq0brjT-R59<}7}t<`#K_p? z>=7z18#NV`KOdU9q`gD5%&sRzXA-gA{jQ*SQ3fu2gTfIg3A`bz!+!Oh^)}C;5tS?) z+RR)+>VVZ>y$NTr4W%*ls}&~_5fa*P5VZTU+LxKgSpQE{LT3Ty&3fgYBbZao~pvS>g9iA5-CJ!n$QNg@3gKBh(Wbl$D*=tKP*X#+VBXBuZ+Lb49 zN+|B_{OsCEsAS{b4|lDJS=dHwVI*!t23T5-s5o}I7(BDSmF&rkg5LL*BttnYmFL5fs7B~8Y< zeiXsnu-}RHHf69=anyWl_LarNxRxu2#vn~ulQiAsRB6zk;>Y=bXm=ZtXxCjQgu%70 zd8$o+EWcCnN7&d!@8 z@se=ABo-+5qW9w~al35gK(X5RMo01%{g=KDs^i}`>RdQ3%Su_vU#hE5nL+*D=1)cb zd4;z#eA&1qWJU z9v~?`lqm5mn22LcYdMD#2(t>KurU<)+zp-8Q-A)g$ssk?rO6$s0#uN{Ccxq0)u_MH zXeNp4?Snp(MRQJ>j4&F-Q`SOOYO$UM_bNZ~qE$iLN;f~d&`@R1^ujrjtRPqcK2vkg z+FK@HwuzWK`64(@QJ66`LCrctMGK?Imz-RKkMX=k<2~$4!n?D!dL zkzB}*lx-I!b*g4-)h(vl-WVf92y6MPKdg|@ONY-koMNc%=am9 ziC0=@qv@eOcLgP~O)~05bsv<=&%Wpj+#{L0lPIlWF(O`R|He7vk(w&Cnp}mW;E5!9vMWc%jwQyZ1MqTNosv3HYRS4lr z5w8ol6!$=%R#XkKbvujCD@M2kwSNcsk2KOxdFW4W?~5h;n5~)U`}p}-WMD6rA&d*( zAl6-xfL`v!cSd*dA8^Uv&rA8JI_0jS3hjjOe^V=02|6Z9$7F&d<7V)DinVaR?AJl8 zH#3f!P!@17G-y6eeP+JBl%G{n%ooO%&rHg7Q0-9%S>(06^CFY0_wC6%Pq0+6Iz6ehM))8>3(YLr>m=ie69*4s&Fd1+rj z$q@+f#Xe+~uZd-hzw{YH+QQe!<0lGXm$s%a;=0|+iA$G~`??33u2{vjhx+ZHjb!=_ zzr^zWv8L(;V1=U~|JN(UWBJ|9K`f^)HF+Y|mLO3A0WT43yxr+T>))FgEgk;BJFi-c zXlxlY`di)4E!yjv30b{_Xsc5Fu)!EB?yPGXcwr&l(nIy3%i z9h@R_swrWL8y_b4jnb=6kZWaiJZgY%8_(Y_m^sSYR~QM^V07k^3%4jcAEHCw6yGi& zX%5nsD|c*?xWDaZ+A4KymKb3b#I=jE9g1bNqw6w0pP{uVy-4ja2EZta2+cEwmD9H{4Vehx*mx zM$Cly89Q#GmZufW80JK+BiFxu1Slu2bl`>n>DBC>!A zp>`cG&q#7vy+4Vq{`M-qC2gO7<43rn8kml-_vRMy#4jN)f8${M-5f()0h?_=rKuLX z$0($K4psWr$X|)Tnyz5%w^HTdsrS!oMqj)Y0(ywX`r_0!#;-!_5otBzp8Habw-N&r zzpf$Cjy&TW9bMwr6t8@cN3%nX$5og>!crc_ei%zSuzZLqy1Me&fW`Op?E$Ql80+ux z>~mj3FeFJP##;H)-#;wjoK$DR}8PC#WaA_zp-bS`|%<8GY{)LEAz;b`D@VhzJ|8kU8lr` z3t=-xU8xenz~80gI-))Z~S1M!#u-$MJ&4m_Joa|Jp@^o%ApQR@+AmJC&x2NQgzwqwil5r_r6z>{;0Ft})^MrfRcITUlPj{E=DE9zPL3@hg5O z-**F%pF4}{X5JJnum$bgQ*4LvFO?v-7r1R_>31+6A*uT8K7T3`-Y zz~qNxQm2h5@E6}X?Og(60Gm!p!3ZJ-#*tk|-XS4oWY%r0zQ5xL4&A+N6H5lT#hX@q3b6 zukNVvrE6^LRSvX|DJ+b}3Yz4(j*uX!sCG`@zroCwyx#^b28!Zi^ z+rC0lZ^bupx0iom-p;`f-)Do0hpFwt=2Hh0oKocB>HCOb;&dTAOut=7^l=w36syk? zAAhlw&@iNG){0b4%D;i=!@G}wJTH9PUF}_M(#K(z!vDnsDEdO+w}1|_Y%6GHsL%^v z8+Mm>*Y*wD5mXdHt=g*paLMS5Mn{lSxg`5W;H0Ak661y5n@swPMKyc>Gml-5T6#V9 zkyH%_kaKVe${JPg_f^RkZ0!dvZ6h5q!D|K%Bcbi9#lwA$Ejfo1BO4y(P+5);a@-#E zSXKv&333RzxcQ-|;TM|ZNGfli?-4zCx<@g4uOm2y`kYsTDVTO))I__z%1u9{`~LyBUN4&g?@6CF*z>5zhc0GO1;2 zT%14HS+4sdLJ8KGb1BM6SP4NF80aXgg*EKGX`Ul6%jC=C+?CU_(qXZeCzymI-E*)C zM{5#OT%3foU9m3vOe)>@d06h{=|fJ!R$H!CctNY4uiqaGA&@~kRbV4;eq%Sl>nhDH z>ay)_Vu{ctiIV67*_!XT8MlfA@&=#w(>n~1s(xJ`r^jD2B6N%}!9xEQcQ(e^DjnK5 zeDZR=T`{yJWa|*CRdU;7c)Vq6Uj_C!=|-5dl{fHe=ntfz@C5F>It z2JyH})pg^84iAeV*O{9k>{VnRMlc5xH^$&l=Go;GJ6Y5Q$d@E)jWU(|Y z)wL9CcGQ}BjURWEZ0;PrS$5J57bnSE|ACV?ac5uHMaZSu+9?#;3Hy>y%sCF3RDJOb zBRBT1Wnfn|s#*)#cmyD`_2zYsR!##+ardM>)RH}I)VZd}Ccj(imUS()MwDC&>_!Ha z%CxJh7Dw^yKrEJyGd0q0yCRUG-lnUyi6AL9UZEY!MWaVwXk}~Epg9t?38j?(c#+mP z+UhVLYM@fpTVH8KJU_k;5wS00Q@4Lv!(FqI&poRACX&F1n@Kh-G{U{zDp`uZ!eMyl zQeTGH197KtY)RQvqATtFblPr4RoyGC<0Vt;7c~NnUqJ5~CDrS=7unyL+00q%a$6;5 zHTa-L=2{=BJ4xH-<8?8<&MWk&%wkm|)C_JOLnYPw>bP~$wehvdAsV>_cI=hye0iGr z;KCyAoRBRpbFN!f=Q?A?wj;YsXq##mO+bSdwI2ya1EUIk*^tLl3vc<3u&cz+ysq7H z5q{a^Ef$b)}i*> z=V#!CYy1#rn!mT8A&=vA>oTh9;p0cRYVnoMbuk8n(6y#4jn8Oh>nFfK{Ec)ld|9(x zn^f;gJpMKh!>l&I@@;|jv`?=olGzyr-Tky=L;90psMYh^7pnbl&v+ILFz?u~-H z99K%95i)jUI7lK(R6&N6M`S~FiIspF%;QM9)28u_S`KU2;Y| zoY`_UkurC~=UODP^x#B}!;)CtyO;>C&gW&{NcX0o^{dwJWfF=)rY@;mhfVFtH!EFI zY$HTO$w~PA7#eq&qSzs#7R8xn!=-Z{OEscECXo^4a|IjogzCn*MctjOc%ogei zYFNuZm0knMv`<}@iZ*sWR|J~q)Y56*NzlJ%2>VelBO;yRmVBx0aKfxZH$rr1HoH2qjaq$5u6AP# z6!1mrgs32*HI}tp`D?}JxG}k$kVq}}V7L4Ywri#qKTAAp2Vr`7@2%C95s73&XcDhN5Mr@TTU2r}k{nkR!u=OK;tW1MWgT>1E9v+p#dOYkRllYV+C)>qH? zWaYCsvm_S_G3YHqu*fsNqImnp#Etb2fG(TzU#GSdR~e;!`FQQ5WjVLm7igJw@zQ{k z)bjfa!)(OOYBjU}pUwo8J~mFtRp55*gX*B*oqs;7pd8R!&;1!xHDI%|CWzkkfp!6g;eFZlB33x(y_!)qp1BQL8F!k zZg5G?50}IZ^FmuRjTse0stSBc^Y_fUJ{xg(zLCA*Y-v;SBTMSu z5i_c<7=?=!rCAevKE@Ph9RBy@Z_5v|7+UyGmRImlO< zt2p((-1*$PZVh*p(x_!RS*zZ~|Gsz`oR$cwWccx=&cIl!Z~wis=9vH+?q0PoO(T4J zM+PbqABEUn8H2H&^IbAZPYP}Ip^!x;iRe7S0*5hj^G=|FKwYVkAe27obww%2h1~L_ za1;8zv!cfZ)hM=ix5#_>_6*;Fr_ zcLs8q6J76yPK7GqIkNRTBi_)P))oO3d$-3ZxFZ*;fuoM;;@4Hw9tZz-(a(pK}RK<5hDs}4E1t@s6343nSb<~Oic#qu)k!BYsUD2iZ8iurkhC%&a1jz+ylhnxG9*hAAL+T8+^F43?3ud!f>JmLdW+d@!`$s<)q8__0>_6& z5Wh|JqAJOdAQxjF@!VTK2yLq)0h_gJZ0H#ycTi#pX)ap8#=Qd`0ElO?v!^&)}idj4pmI zzAN@}fl2{Q_+pn2seBtn8gH?(6gocp%1_~pTCWRzx|rDT-5!Dqp96(_WskP(W!;GV zP=2XJAXw^#S9-Z(0~2PgFM&nOumK79ImczY{DMxSxLSodHLbtEUZ1Dob?*Lq*IA=Q zN@hZ*rM-FDtom^Ex=MKbhK*yFgus>fwmIxv^UxEOo;>rO6H` z7lWQ@qO9P|HIxGcAykl!lQ6P!C4DYdVq;TS|9cb4bv^#b6%OcDuTRlG4f;DqFenA+ z-^KImN#_2TlIo`IuP??8#)HMt&>UbcvGg^Ka>CiMD8Yf*ME}a9Sl9M zlVlXR!s}ZWDs>1H8dxkBMEA2w4tzMOmty)n<%8SY+oTIoDl8Wh~5ZOGM|^w(z3YfL(e{;Yuf`Vx0|R_QLD zJG>eRP2k(A+L^^%3tn1g!JOefPhWMcI?GDA%J&U>5rT9@qIBVCz*H$Mm*fncGN#RZC1!tUVrxs#;yCA5pU&c~(Chv2urX`8^8JC~6zJ1o zTPm#Fhl|M!@UNAY{o`eyRiE>L)s7|DDtzso9QXPSwx> zqeM!ibot>(V~ZG1XGo;Fknmy8CP_K*>#7+bxv?)Ks8GmrA;=Q;t|!7EH(ga)G>@ji zwwbYt!bKmb)tv_1cB>Tw?)TQ^EmypO21UMOQY4m}PqV(zz0HfuSy*2=Qs#774AQMB z5dXwzqI>GJq-N4gL{^<3B~jmZE+6N%t9sV$;vQw>x@Vr#52=e0aX(K?NVr5q?KOr0?g>FH6B=G!4i->2m;!# zkQcFxrcRJ4yt4R;x7nL$#RIKKBCU`?c2uXSSgjN}6NbAVY{UQK98EKtW^oKlk~cBM zpHFJgjtfgQOf%C)Z18S+Nva4xs*h7i&*;rP`fD1OmNHg$>!GmL5LMTVs1l?KYe-Nn z?8`>Bw;UVm!Y~6f^s;HQxqWDT%Ahw}^=<{-b$qJR9}1Wic@CV2%_9PEQ5H=L%8Gv2 z8H{f?X3Z1@lgeoDg43{8%NK$yMuRNPg~Hx(W_Gx7exrDinwj=@ubwVDLENU<5>iy<&?4NfjrxZFkpR-QCt5ty|`%$l{1Z=r3sg@YPl74~r= z%tt)a=a1LkMkJNu@RwV>KK43kk5bi7IE50qSfd7#Z{h&6H@JY=ncK5Fl|O2{_YtV@!siW=6pPk(U@l`MR%+W(pm>>Sco zcOp`1VXI@4-fe%kytV+;}q`OXyLN9^h(5s-XpSG|R`UXSxy$mopIqf5neFsBT(I@gI2>)F416oU`=k{S6 zMYd#h{lUJNw)dxo>rz#a2v~8zR7Kvsm~JS<%q)~-^b(ben;>QSXH!6Q`ok5@*nC2v zrO)trKY!1LVAmIu=C4>5Ice=Sffw&*#m|1-r~<6YCO%$po5^@{?6!$~*7hy7F2B^!QM53P|fRM0foa zkMG62M+b5+$!vkT>ROwim+yH8vl2ARKJn%TLeG>Op2zV(fc!UoXXY~c)2c*eYa9fsYw#nD<#=#H*s4PDIKG!u;k2s{b> zJOy4pPE+XvM6?6nYW0wU(fMLTTToFuhrg81%BCPc{HHTUezE+pR4lC%TmD)5J+d{k zx)ZAbc@nn0nE!$i4v$1|gjJvWLGgdS~b8Tgy^U?|F`nvHs227?CXBuWU_q(?0N^$Fz)+OnwUX)yCy%C+I~qDz+=vYc=@AXx-)lJr z_A;UYwK%{~Vjf&+Q{}=1Qo<=U%RO$;TT_#zbA5xNTT{Nd%P{q6NzI&3y|hi+v>wY! zW2wiyW;#vfyj(vsfpZBVLbI{Xd*AIx@ik-GGZNo0PlSgW)h#9qghSFGHs*XKQ-o5G)WWsGumz>ulFmiE;pgzl{I>S12mHyMu>6yE% z;oFv=0Rv7}AX$RID~+OjfMO{Da?c9(r;uNkRqi$qa57FUo=$TPvIcMIm{PpgT8u64 z|G#~oKXU|o8Z*KE5o!yK!=SPLNSub|F$Ir7+I{@egQr|yfKAOBpD|?S_t4K0h1Kp~ z3Dq_p>WL>xVD&J7004yH006>IJltWD+GD#Zgl9^xD;dnQwCy1PgZ{@9mG_WtJRAU! ziUx)X!UH?Spwue+6u~{CZvAhdo~5h6uYa#G5i$8}jMGlLLE*7w3HFgK^JHvbl&1D3 zO5?9rsxgJw&*ZzDlfSx?yw$(bbYVU0^Vz5}XqYGO8#=4rr957+4gk`wkeR^)yJzI-OO zJQBZ(JP{B2sGo@cd71Vww{f#7jtBCy~f z>a$*PkO+F*09+kK4UQPZdDi7T>Y5FobZdij&pMPLBIs5V@aZ@MSY?Rn$&p=Zv@_X9 zClnuV4vv2uDKdW~lYlFRsGorU-2eXoMJ&OmLyFH9#DvVf^McD@x{H6c-iWzqL6NQg{7yO?!O!9d$ zUpn$PXrm)U&|p7sS{W4>dGxtzfGI|aplw6I%Mn6G zkL1JfM;#SdVC?S&RmO;*Q!>EDt@Pl8G2k<<`cW5^{Wse1;JY#GCqtgJ8yZHBeQ-o5 zk2T~ULyn&xmsa>c%jz>u1WjM~=sD~EPWzua_79o0WvXj$kVazMo+m>T?T;%}lrO%g%()qqJSWuIJT!LtfPcwD}gN4GiuA*R$l u5m}nC!0f}%f&8aN{sTU4cnpy6)6MdKE9HNXbpavGk9Cs+9;xMz^8W#n`xw>$ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 864f396..1360c1c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ -#Tue Aug 05 03:26:05 IDT 2014 +#Wed Jan 27 00:30:26 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-all.zip -distributionSha256Sum=4647967f8de78d6d6d8093cdac50f368f8c2b8038f41a5afe1c3bce4c69219a9 +distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..9d82f78 100755 --- a/gradlew +++ b/gradlew @@ -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` diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index f9936c7..6258f5f 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -110,7 +110,7 @@ public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); - Pair originalCipher = new Pair<>( + Pair originalCipher = new Pair( curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); Pair newCipher = elGamalPK.add(originalCipher, randomizer); diff --git a/settings.gradle b/settings.gradle index 99f4c5e..5f81a65 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,5 @@ include 'bulletin-board-server' include 'polling-station' include 'restful-api-common' include 'bulletin-board-client' +include 'destributed-key-generation' From 93240c10f469517706b34e1bd78b88c702173188 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Thu, 28 Jan 2016 01:47:07 +0200 Subject: [PATCH 010/106] tested interpolation --- .../VerifiableSecretSharing.java | 16 ++--- .../LagrangePolynomial.java | 40 ++++++++++++ .../java/ShamirSecretSharing/Polynomial.java | 58 ++++++++++++------ .../ShamirSecretSharing/SecretSharing.java | 13 ++-- .../src/test/java/Polynomial/AddTest.java | 44 +++++++++++++ .../java/Polynomial/InterpolationTest.java | 61 +++++++++++++++++++ .../test/java/Polynomial/MulByConstTest.java | 46 ++++++++++++++ .../src/test/java/Polynomial/MulTest.java | 46 ++++++++++++++ .../src/test/java/Polynomial/Utils.java | 21 +++++++ 9 files changed, 313 insertions(+), 32 deletions(-) create mode 100644 destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java create mode 100644 destributed-key-generation/src/test/java/Polynomial/AddTest.java create mode 100644 destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java create mode 100644 destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java create mode 100644 destributed-key-generation/src/test/java/Polynomial/MulTest.java create mode 100644 destributed-key-generation/src/test/java/Polynomial/Utils.java diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index fea7a1b..1b44693 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -2,6 +2,7 @@ package FeldmanVerifiableSecretSharing; import ShamirSecretSharing.SecretSharing; import org.bouncycastle.util.Arrays; +import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; @@ -15,9 +16,9 @@ public class VerifiableSecretSharing extends SecretSharing { private final BigInteger[] commitments; private final BigInteger g; - public VerifiableSecretSharing(Zpstar zpstar, int t, int n, BigInteger s, Random random) { - super(zpstar, t, n, s, random); - this.g = BigInteger.ONE; //ToDO zpstar.getGenerator() + public VerifiableSecretSharing(CyclicGroup group, int t, int n, BigInteger s, Random random) { + super(group, t, n, s, random); + this.g = group.getGenerator(); this.commitments = generateCommitments(); } @@ -25,7 +26,7 @@ public class VerifiableSecretSharing extends SecretSharing { BigInteger[] coefficients = polynomial.getCoefficients(); BigInteger[] commitments = new BigInteger[coefficients.length]; for (int i = 0 ; i < commitments.length;i++){ - commitments[i] = zpstar.multiply(g,coefficients[i]); + commitments[i] = group.multiply(g,coefficients[i]); //(g ^ coeff[i]) % p } return commitments; } @@ -34,13 +35,14 @@ public class VerifiableSecretSharing extends SecretSharing { if(i < 1 || i > n){ throw new Exception(); } - BigInteger v = BigInteger.ONE; + BigInteger v = group.zero(); int power = 1; for (int j = 0 ; j < commitments.length ; j ++){ - v.multiply(commitments[i].pow(power)); + v = group.add(v,commitments[i].pow(power)); power *=i; } - return zpstar.add(BigInteger.ONE,v); + + return group.add(group.zero(),v); } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java new file mode 100644 index 0000000..fbaa893 --- /dev/null +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java @@ -0,0 +1,40 @@ +package ShamirSecretSharing; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 1/28/2016. + */ +class LagrangePolynomial{ + public final Polynomial polynomial; + public final BigInteger image; + public final BigInteger divisor; + + private LagrangePolynomial(Polynomial polynomial, BigInteger image, BigInteger divisor) { + this.polynomial = polynomial; + this.image = image; + this.divisor = divisor; + } + + public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points){ + 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[]{BigInteger.ZERO.subtract(points[i].x),BigInteger.ONE}); // X - Xi + } + Polynomial product; + BigInteger divisor; + for(int i = 0; i < points.length; i ++) { + product = Polynomial.ONE; + divisor = BigInteger.ONE; + for (int j = 0; j < points.length; j++) { + if (i != j) { + divisor = divisor.multiply(points[i].x.subtract(points[j].x)); + product = product.mul(factors[j]); + } + } + lagrangePolynomials[i] = new LagrangePolynomial(product,points[i].y,divisor); + } + return lagrangePolynomials; + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index 69b4da5..b1dddcc 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -2,6 +2,7 @@ package ShamirSecretSharing; import org.bouncycastle.util.Arrays; import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.util.Pair; import java.math.BigInteger; @@ -10,8 +11,8 @@ import java.math.BigInteger; */ public class Polynomial { - private static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); - private static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); + protected static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); + protected static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); private final int degree; private final BigInteger[] coefficients; @@ -25,36 +26,53 @@ public class Polynomial { this.coefficients = polynomial.getCoefficients(); } + public boolean isEquals(Polynomial other) { + if (this.degree != other.degree) + return false; + return Arrays.areEqual(this.coefficients,other.coefficients); + } + + @Override + public String toString() { + return "Polynomial{" + + "degree=" + degree + + ", coefficients=" + java.util.Arrays.toString(coefficients) + + '}'; + } + public BigInteger image(BigInteger x){ BigInteger result = BigInteger.ZERO; BigInteger power = BigInteger.ONE; for(int i = 0 ; i <= degree ; i++){ - result.add(coefficients[i].multiply(power)); - power.multiply(x); + result = result.add(coefficients[i].multiply(power)); + power = power.multiply(x); } return result; } public static Polynomial interpolation(Point[] points){ - Polynomial[] factors = new Polynomial[points.length]; - for (int i = 0 ; i < factors.length ; i++){ - factors[i] = new Polynomial(new BigInteger[]{BigInteger.ONE,points[i].x}); // X - Xi + LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points); + + BigInteger product = BigInteger.ONE; + for (int i = 0; i < l.length;i++){ + product = product.multiply(l[i].divisor); } - Polynomial result = ZERO; - BigInteger constant; - Polynomial product; - for (int i = 0 ; i < points.length; i++){ - constant = points[i].y; - product = ONE; - for (int j = 0 ; j < points.length; j ++){ - if(i != j ) { - constant = constant.divide(points[i].x.subtract(points[j].x)); - product = product.mul(factors[j]); - } + + BigInteger[] factors = new BigInteger[l.length]; + for (int i = 0; i < l.length;i++){ + factors[i] = product.divide(l[i].divisor); + } + + int degree = l[0].polynomial.degree; + 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++){ + coefficients[j] = coefficients[j].add(l[i].image.multiply(factors[i]).multiply(l[i].polynomial.coefficients[j])); } - result.add(product.mul(constant)); + coefficients[j] = coefficients[j].divide(product); } - return result; + return new Polynomial(coefficients); } public Polynomial add(Polynomial other){ diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 4457f95..0fe9d6a 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -1,6 +1,7 @@ package ShamirSecretSharing; +import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; @@ -10,13 +11,13 @@ import java.util.Random; * Created by Tzlil on 1/27/2016. */ public class SecretSharing { - protected final Zpstar zpstar; + protected final CyclicGroup group; protected final int t; protected final int n; protected final Polynomial polynomial; - public SecretSharing(Zpstar zpstar, int t, int n, BigInteger s, Random random) { - this.zpstar = zpstar; + public SecretSharing(CyclicGroup group, int t, int n, BigInteger s, Random random) { + this.group = group; this.t = t; this.n = n; this.polynomial = generateRandomPolynomial(s,random); @@ -25,13 +26,15 @@ public class SecretSharing { private Polynomial generateRandomPolynomial(BigInteger s, Random random) { BigInteger[] coefficients = new BigInteger[t + 1]; coefficients[0] = s; + BigInteger p = group.orderUpperBound(); + int bits = p.bitLength(); for (int i = 1 ; i <= t; i++ ){ - coefficients[i] = zpstar.sample(random); + coefficients[i] = new BigInteger(bits,random).mod(p); // sample from Zp [0,... p-1] } return new Polynomial(coefficients); } - //ToDo make it safe : permission to call this func + modulo calc + //ToDo make it safe : permission to call this func public Polynomial.Point getShare(int i) throws Exception { if(i < 1 || i > n){ throw new Exception(); diff --git a/destributed-key-generation/src/test/java/Polynomial/AddTest.java b/destributed-key-generation/src/test/java/Polynomial/AddTest.java new file mode 100644 index 0000000..7e002a1 --- /dev/null +++ b/destributed-key-generation/src/test/java/Polynomial/AddTest.java @@ -0,0 +1,44 @@ +package Polynomial; +import ShamirSecretSharing.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] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + arr2[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + } + } + + public void oneTest(Polynomial p1, Polynomial p2){ + Polynomial sum = p1.add(p2); + BigInteger x = new BigInteger(bits,random); + assert(sum.image(x).equals(p1.image(x).add(p2.image(x)))); + } + + @Test + public void addTest(){ + for (int i = 0 ; i < arr1.length; i ++){ + oneTest(arr1[i],arr2[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java b/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java new file mode 100644 index 0000000..25595c7 --- /dev/null +++ b/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java @@ -0,0 +1,61 @@ +package Polynomial; + +import ShamirSecretSharing.Polynomial; +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; + @Before + public void settings(){ + random = new Random(); + polynomials = new Polynomial[tests]; + pointsArrays = new Polynomial.Point[tests][]; + for (int i = 0; i < polynomials.length; i++){ + polynomials[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + pointsArrays[i] = randomPoints(polynomials[i]); + } + } + + public Polynomial.Point[] randomPoints(Polynomial p){ + Polynomial.Point[] points = new Polynomial.Point[p.getDegree() + 1]; + BigInteger x; + Boolean b; + Set set = new HashSet(); + for (int i = 0; i < points.length; i++){ + x = new BigInteger(bits,random); + if(set.contains(x)){ + i--; + continue; + } + set.add(x); + points[i] = new Polynomial.Point(x,p.image(x)); + } + return points; + } + + public void oneTest(Polynomial p, Polynomial.Point[] points){ + Polynomial interpolation = Polynomial.interpolation(points); + assert (p.isEquals(interpolation)); + } + + @Test + public void interpolationTest(){ + for (int i = 0; i < polynomials.length; i ++){ + oneTest(polynomials[i],pointsArrays[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java b/destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java new file mode 100644 index 0000000..b0ddad2 --- /dev/null +++ b/destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java @@ -0,0 +1,46 @@ +package Polynomial; + +import ShamirSecretSharing.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] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + 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.image(x).equals(p.image(x).multiply(c))); + } + + @Test + public void mulByConstTest(){ + for (int i = 0 ; i < arr1.length; i ++){ + oneTest(arr1[i],arr2[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/Polynomial/MulTest.java b/destributed-key-generation/src/test/java/Polynomial/MulTest.java new file mode 100644 index 0000000..a60c986 --- /dev/null +++ b/destributed-key-generation/src/test/java/Polynomial/MulTest.java @@ -0,0 +1,46 @@ +package Polynomial; + +import ShamirSecretSharing.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] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + arr2[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + } + } + + public void oneTest(Polynomial p1, Polynomial p2){ + Polynomial product = p1.mul(p2); + BigInteger x = new BigInteger(bits,random); + assert(product.image(x).equals(p1.image(x).multiply(p2.image(x)))); + } + + @Test + public void mulTest(){ + for (int i = 0 ; i < arr1.length; i ++){ + oneTest(arr1[i],arr2[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/Polynomial/Utils.java b/destributed-key-generation/src/test/java/Polynomial/Utils.java new file mode 100644 index 0000000..e52dd9b --- /dev/null +++ b/destributed-key-generation/src/test/java/Polynomial/Utils.java @@ -0,0 +1,21 @@ +package Polynomial; + +import ShamirSecretSharing.Polynomial; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class Utils { + + public static Polynomial generateRandomPolynomial(int degree,int bits,Random random) { + BigInteger[] coefficients = new BigInteger[degree + 1]; + + for (int i = 0 ; i <= degree; i++ ){ + coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... p-1] + } + return new Polynomial(coefficients); + } +} From 8ba55bacd20b389af365edadc2d5572fe2d24991 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Thu, 28 Jan 2016 13:57:47 +0200 Subject: [PATCH 011/106] feldmanVSS documention --- .../VerifiableSecretSharing.java | 41 ++++++-- .../LagrangePolynomial.java | 26 ++++- .../java/ShamirSecretSharing/Polynomial.java | 96 +++++++++++++++---- .../ShamirSecretSharing/SecretSharing.java | 48 ++++++++-- .../java/Polynomial/InterpolationTest.java | 4 +- 5 files changed, 180 insertions(+), 35 deletions(-) diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 1b44693..1554bf6 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -13,43 +13,64 @@ import java.util.Random; */ public class VerifiableSecretSharing extends SecretSharing { + private final CyclicGroup group; + private final BigInteger g; // public generator of group private final BigInteger[] commitments; - private final BigInteger g; + + /** + * @param group a cyclic group of prime order p. + * it must be chosen such that computing discrete logarithms is hard in this group. + */ public VerifiableSecretSharing(CyclicGroup group, int t, int n, BigInteger s, Random random) { - super(group, t, n, s, random); + super(group.orderUpperBound(), t, n, s, random); + this.group = group; this.g = group.getGenerator(); this.commitments = generateCommitments(); } + /** + * @return commitments[i] = g ^ polynomial.coefficients[i] + */ private BigInteger[] generateCommitments() { BigInteger[] coefficients = polynomial.getCoefficients(); BigInteger[] commitments = new BigInteger[coefficients.length]; for (int i = 0 ; i < commitments.length;i++){ - commitments[i] = group.multiply(g,coefficients[i]); //(g ^ coeff[i]) % p + commitments[i] = group.multiply(g,coefficients[i]); } return commitments; } - public BigInteger verify(int i) throws Exception { - if(i < 1 || i > n){ - throw new Exception(); - } + /** + * @param i share holder id + * @param commitments + * @param group + * + * @return product of commitments[j] ^ (i ^ j) == g ^ polynomial(i) + */ + public static BigInteger verify(int i,BigInteger[] commitments,CyclicGroup group) { BigInteger v = group.zero(); int power = 1; for (int j = 0 ; j < commitments.length ; j ++){ v = group.add(v,commitments[i].pow(power)); power *=i; } - - return group.add(group.zero(),v); + return v; } - public BigInteger getG() { + /** + * getter + * @return generator of group + */ + public BigInteger getGenerator() { return g; } + /** + * getter + * @return copy of commitments + */ public BigInteger[] getCommitments() { return Arrays.clone(commitments); } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java index fbaa893..d3815ff 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java @@ -4,19 +4,41 @@ import java.math.BigInteger; /** * Created by Tzlil on 1/28/2016. + * + * container of lagrange polynomial + * + * can't be constructed, constructor is private + * + * l = (image/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; } - public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points){ + /** + * 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 + * + * @throws Exception there exists i != j s.t points[i].x == points[j].x + */ + public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points) throws Exception { LagrangePolynomial[] lagrangePolynomials = new LagrangePolynomial[points.length]; Polynomial[] factors = new Polynomial[points.length]; for (int i = 0 ; i < factors.length ; i++){ @@ -33,6 +55,8 @@ class LagrangePolynomial{ product = product.mul(factors[j]); } } + if(divisor.equals(BigInteger.ZERO)) + throw new Exception(); lagrangePolynomials[i] = new LagrangePolynomial(product,points[i].y,divisor); } return lagrangePolynomials; diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index b1dddcc..620e1e7 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -9,27 +9,39 @@ import java.math.BigInteger; /** * Created by Tzlil on 1/27/2016. */ -public class Polynomial { - - protected static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); - protected static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); +public class Polynomial implements Comparable { + protected static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); // neutral for add + protected static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); // neutral for mul private final int degree; private final BigInteger[] coefficients; + /** + * constructor + * @param coefficients + * degree set as max index such that coefficients[degree] not equals zero + */ public Polynomial(BigInteger[] coefficients) { - this.degree = coefficients.length - 1; + int d = coefficients.length - 1; + while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){ + d--; + } + this.degree = d; this.coefficients = coefficients; } - public Polynomial(Polynomial polynomial) { - this.degree = polynomial.getDegree(); - this.coefficients = polynomial.getCoefficients(); - } - public boolean isEquals(Polynomial other) { + @Override + public int compareTo(Polynomial other) { if (this.degree != other.degree) - return false; - return Arrays.areEqual(this.coefficients,other.coefficients); + 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; } @Override @@ -40,6 +52,11 @@ public class Polynomial { '}'; } + + /** + * @param x + * @return sum of coefficients[i] * (x ^ i) + */ public BigInteger image(BigInteger x){ BigInteger result = BigInteger.ZERO; BigInteger power = BigInteger.ONE; @@ -50,20 +67,28 @@ public class Polynomial { return result; } + /** + * @param points + * @return polynomial of minimal degree which goes through all points + */ public static Polynomial interpolation(Point[] points){ LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points); + // product = product of l[i].divisor BigInteger product = BigInteger.ONE; for (int i = 0; i < l.length;i++){ product = product.multiply(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] = product.divide(l[i].divisor); } - int degree = l[0].polynomial.degree; + + // coefficients[j] = (sum of l[i].image * factor[i] * l[i].coefficients[j] s.t i!=j) divide by product = + // = sum of l[i].image * 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; @@ -75,6 +100,11 @@ public class Polynomial { return new Polynomial(coefficients); } + /** + * @param other + * @return new Polynomial of degree max(this degree,other degree) s.t for all x in Z + * new.image(x) = this.image(x) + other.image(x) + */ public Polynomial add(Polynomial other){ Polynomial bigger,smaller; if(this.degree < other.degree){ @@ -92,6 +122,11 @@ public class Polynomial { return new Polynomial(coefficients); } + /** + * @param constant + * @return new Polynomial of degree this.degree s.t for all x in Z + * new.image(x) = constant * this.image(x) + */ public Polynomial mul(BigInteger constant){ BigInteger[] coefficients = this.getCoefficients(); @@ -102,6 +137,11 @@ public class Polynomial { return new Polynomial(coefficients); } + /** + * @param other + * @return new Polynomial of degree this degree + other degree + 1 s.t for all x in Z + * new.image(x) = this.image(x) * other.image(x) + */ public Polynomial mul(Polynomial other){ BigInteger[] coefficients = new BigInteger[this.degree + other.degree + 1]; @@ -116,21 +156,45 @@ public class Polynomial { } + /** getter + * @return copy of coefficients + */ public BigInteger[] getCoefficients() { return Arrays.clone(coefficients); } + + /** getter + * @return degree + */ public int getDegree() { return degree; } - + /** + * inner class + * container for (x,y) x from range and y from image of polynomial + */ public static class Point{ public final BigInteger x; public final BigInteger y; - public Point(BigInteger x, BigInteger y) { + /** + * constructor + * @param x + * @param polynomial y = polynomial.image(x) + */ + public Point(BigInteger x, Polynomial polynomial) { this.x = x; - this.y = y; + this.y = polynomial.image(x); + } + + /** + * copy constructor + * @param point + */ + public Point(Point point) { + this.x = point.x; + this.y = point.y; } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 0fe9d6a..d3c48c9 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -9,48 +9,84 @@ import java.util.Random; /** * Created by Tzlil on 1/27/2016. + * an implementation of Shamire's secret sharing scheme */ public class SecretSharing { - protected final CyclicGroup group; protected final int t; protected final int n; + protected final BigInteger p; protected final Polynomial polynomial; - public SecretSharing(CyclicGroup group, int t, int n, BigInteger s, Random random) { - this.group = group; + /** + * constructor + * @param p 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 s secret, chosen from Zp + * @param random use for generate random polynomial + */ + public SecretSharing(BigInteger p, int t, int n, BigInteger s, Random random) { + this.p = p; this.t = t; this.n = n; this.polynomial = generateRandomPolynomial(s,random); } + /** + * @param s + * @param random + * @return new Polynomial polynomial of degree t ,such that + * 1. polynomial(0) = s + * 2. polynomial coefficients randomly chosen from Zp (except of coefficients[0] = s) + */ private Polynomial generateRandomPolynomial(BigInteger s, Random random) { BigInteger[] coefficients = new BigInteger[t + 1]; coefficients[0] = s; - BigInteger p = group.orderUpperBound(); int bits = p.bitLength(); for (int i = 1 ; i <= t; i++ ){ - coefficients[i] = new BigInteger(bits,random).mod(p); // sample from Zp [0,... p-1] + coefficients[i] = new BigInteger(bits,random).mod(p); } return new Polynomial(coefficients); } //ToDo make it safe : permission to call this func + /** + * @param i in range of [1,...n] + * + * @return polynomial.image(i) + * + * @throws Exception i out of range + */ public Polynomial.Point getShare(int i) throws Exception { if(i < 1 || i > n){ throw new Exception(); } - return new Polynomial.Point(BigInteger.valueOf(i), polynomial.image(BigInteger.valueOf(i))); + return new Polynomial.Point(BigInteger.valueOf(i), polynomial); } + /** + * @param shares - subset of the original shares + * + * @return image of interpolation(shares) at x = 0 + */ public static BigInteger getSecrete(Polynomial.Point[] shares){ Polynomial polynomial = Polynomial.interpolation(shares); return polynomial.image(BigInteger.ZERO); } + /** + * getter + * @return threshold + */ public int getThreshold() { return t; } + /** + * getter + * @return number of share holders + */ public int getN() { return n; } diff --git a/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java b/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java index 25595c7..d08b0f2 100644 --- a/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java @@ -42,14 +42,14 @@ public class InterpolationTest { continue; } set.add(x); - points[i] = new Polynomial.Point(x,p.image(x)); + points[i] = new Polynomial.Point(x,p); } return points; } public void oneTest(Polynomial p, Polynomial.Point[] points){ Polynomial interpolation = Polynomial.interpolation(points); - assert (p.isEquals(interpolation)); + assert (p.compareTo(interpolation) == 0); } @Test From f8d31d16a319572bf170acaf880ae5b01821ab0c Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 29 Jan 2016 22:08:13 +0200 Subject: [PATCH 012/106] FeldmanVSS tests --- .../LagrangePolynomial.java | 2 +- .../ShamirSecretSharing/Polynomial.java | 14 ++-- .../ShamirSecretSharing/SecretSharing.java | 19 ++++-- .../VerifiableSecretSharing.java | 19 ++++-- .../PolynomialTests}/AddTest.java | 4 +- .../PolynomialTests}/InterpolationTest.java | 8 +-- .../PolynomialTests}/MulByConstTest.java | 4 +- .../PolynomialTests}/MulTest.java | 4 +- .../PolynomialTests}/Utils.java | 4 +- .../SecretSharingTest.java | 60 +++++++++++++++++ .../VerifiableSecretSharingTest.java | 64 +++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 12 files changed, 170 insertions(+), 34 deletions(-) rename destributed-key-generation/src/main/java/{ => FeldmanVerifiableSecretSharing}/ShamirSecretSharing/LagrangePolynomial.java (97%) rename destributed-key-generation/src/main/java/{ => FeldmanVerifiableSecretSharing}/ShamirSecretSharing/Polynomial.java (89%) rename destributed-key-generation/src/main/java/{ => FeldmanVerifiableSecretSharing}/ShamirSecretSharing/SecretSharing.java (87%) rename destributed-key-generation/src/test/java/{Polynomial => FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests}/AddTest.java (87%) rename destributed-key-generation/src/test/java/{Polynomial => FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests}/InterpolationTest.java (88%) rename destributed-key-generation/src/test/java/{Polynomial => FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests}/MulByConstTest.java (87%) rename destributed-key-generation/src/test/java/{Polynomial => FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests}/MulTest.java (88%) rename destributed-key-generation/src/test/java/{Polynomial => FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests}/Utils.java (76%) create mode 100644 destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java create mode 100644 destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java similarity index 97% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java rename to destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java index d3815ff..6754822 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java @@ -1,4 +1,4 @@ -package ShamirSecretSharing; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing; import java.math.BigInteger; diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java similarity index 89% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java rename to destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java index 620e1e7..ac340b7 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java @@ -1,8 +1,6 @@ -package ShamirSecretSharing; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing; import org.bouncycastle.util.Arrays; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.util.Pair; import java.math.BigInteger; @@ -46,7 +44,7 @@ public class Polynomial implements Comparable { @Override public String toString() { - return "Polynomial{" + + return "FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests{" + "degree=" + degree + ", coefficients=" + java.util.Arrays.toString(coefficients) + '}'; @@ -71,7 +69,7 @@ public class Polynomial implements Comparable { * @param points * @return polynomial of minimal degree which goes through all points */ - public static Polynomial interpolation(Point[] points){ + public static Polynomial interpolation(Point[] points) throws Exception { LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points); // product = product of l[i].divisor @@ -102,7 +100,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new Polynomial of degree max(this degree,other degree) s.t for all x in Z + * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z * new.image(x) = this.image(x) + other.image(x) */ public Polynomial add(Polynomial other){ @@ -124,7 +122,7 @@ public class Polynomial implements Comparable { /** * @param constant - * @return new Polynomial of degree this.degree s.t for all x in Z + * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree this.degree s.t for all x in Z * new.image(x) = constant * this.image(x) */ public Polynomial mul(BigInteger constant){ @@ -139,7 +137,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new Polynomial of degree this degree + other degree + 1 s.t for all x in Z + * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree this degree + other degree + 1 s.t for all x in Z * new.image(x) = this.image(x) * other.image(x) */ public Polynomial mul(Polynomial other){ diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java similarity index 87% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java rename to destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index d3c48c9..f5629d4 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -1,9 +1,6 @@ -package ShamirSecretSharing; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing; -import org.factcenter.qilin.primitives.CyclicGroup; -import org.factcenter.qilin.primitives.concrete.Zpstar; - import java.math.BigInteger; import java.util.Random; @@ -14,6 +11,8 @@ import java.util.Random; public class SecretSharing { protected final int t; protected final int n; + + protected final BigInteger p; protected final Polynomial polynomial; @@ -36,7 +35,7 @@ public class SecretSharing { /** * @param s * @param random - * @return new Polynomial polynomial of degree t ,such that + * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests polynomial of degree t ,such that * 1. polynomial(0) = s * 2. polynomial coefficients randomly chosen from Zp (except of coefficients[0] = s) */ @@ -70,7 +69,7 @@ public class SecretSharing { * * @return image of interpolation(shares) at x = 0 */ - public static BigInteger getSecrete(Polynomial.Point[] shares){ + public static BigInteger getSecrete(Polynomial.Point[] shares) throws Exception { Polynomial polynomial = Polynomial.interpolation(shares); return polynomial.image(BigInteger.ZERO); } @@ -91,5 +90,11 @@ public class SecretSharing { return n; } - + /** + * getter + * @return the prime was given in the constructor + */ + public BigInteger getP() { + return p; + } } diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 1554bf6..082177f 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -1,9 +1,8 @@ package FeldmanVerifiableSecretSharing; -import ShamirSecretSharing.SecretSharing; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.SecretSharing; import org.bouncycastle.util.Arrays; import org.factcenter.qilin.primitives.CyclicGroup; -import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; import java.util.Random; @@ -50,10 +49,11 @@ public class VerifiableSecretSharing extends SecretSharing { */ public static BigInteger verify(int i,BigInteger[] commitments,CyclicGroup group) { BigInteger v = group.zero(); - int power = 1; + BigInteger power = BigInteger.ONE; + BigInteger I = BigInteger.valueOf(i); for (int j = 0 ; j < commitments.length ; j ++){ - v = group.add(v,commitments[i].pow(power)); - power *=i; + v = group.add(v,group.multiply(commitments[j],power)); + power = power.multiply(I); } return v; } @@ -74,4 +74,13 @@ public class VerifiableSecretSharing extends SecretSharing { public BigInteger[] getCommitments() { return Arrays.clone(commitments); } + + + /** + * getter + * @return the cyclic group was given in the constructor + */ + public CyclicGroup getGroup() { + return group; + } } diff --git a/destributed-key-generation/src/test/java/Polynomial/AddTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java similarity index 87% rename from destributed-key-generation/src/test/java/Polynomial/AddTest.java rename to destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java index 7e002a1..1df4fef 100644 --- a/destributed-key-generation/src/test/java/Polynomial/AddTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java @@ -1,5 +1,5 @@ -package Polynomial; -import ShamirSecretSharing.Polynomial; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java similarity index 88% rename from destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java rename to destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index d08b0f2..71c93fa 100644 --- a/destributed-key-generation/src/test/java/Polynomial/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -1,6 +1,6 @@ -package Polynomial; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; -import ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; @@ -47,13 +47,13 @@ public class InterpolationTest { return points; } - public void oneTest(Polynomial p, Polynomial.Point[] points){ + public void oneTest(Polynomial p, Polynomial.Point[] points) throws Exception { Polynomial interpolation = Polynomial.interpolation(points); assert (p.compareTo(interpolation) == 0); } @Test - public void interpolationTest(){ + public void interpolationTest() throws Exception { for (int i = 0; i < polynomials.length; i ++){ oneTest(polynomials[i],pointsArrays[i]); } diff --git a/destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java similarity index 87% rename from destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java rename to destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java index b0ddad2..6d9669a 100644 --- a/destributed-key-generation/src/test/java/Polynomial/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java @@ -1,6 +1,6 @@ -package Polynomial; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; -import ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/Polynomial/MulTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java similarity index 88% rename from destributed-key-generation/src/test/java/Polynomial/MulTest.java rename to destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java index a60c986..fd4d761 100644 --- a/destributed-key-generation/src/test/java/Polynomial/MulTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java @@ -1,6 +1,6 @@ -package Polynomial; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; -import ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/Polynomial/Utils.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java similarity index 76% rename from destributed-key-generation/src/test/java/Polynomial/Utils.java rename to destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java index e52dd9b..b43869d 100644 --- a/destributed-key-generation/src/test/java/Polynomial/Utils.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java @@ -1,6 +1,6 @@ -package Polynomial; +package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; -import ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java new file mode 100644 index 0000000..d5f8842 --- /dev/null +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java @@ -0,0 +1,60 @@ +package FeldmanVerifiableSecretSharing.ShamirSecretSharing; + +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests.Utils; +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 group; + int tests = 1 << 10; + Random random; + + @Before + public void settings(){ + BigInteger p = BigInteger.valueOf(2903); + group = new Zn(p); + int t = 10; + 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(p,t,n,secrets[i],random); + } + } + + public void oneTest(SecretSharing secretSharing, BigInteger secret) throws Exception { + int t = secretSharing.getThreshold(); + int n = secretSharing.getN(); + Polynomial.Point[] shares = new Polynomial.Point[t + 1]; + List indexes = new ArrayList(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()))); + } + assert(secret.equals(SecretSharing.getSecrete(shares))); + } + + @Test + public void secretSharingTest() throws Exception { + for (int i = 0 ; i < secretSharingArray.length; i ++){ + oneTest(secretSharingArray[i],secrets[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java new file mode 100644 index 0000000..8846cd9 --- /dev/null +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -0,0 +1,64 @@ +package FeldmanVerifiableSecretSharing; + +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.SecretSharing; +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 VerifiableSecretSharingTest { + + + VerifiableSecretSharing[] verifiableSecretSharingArray; + int tests = 1 << 10; + Random random; + + @Before + public void settings(){ + BigInteger p = BigInteger.valueOf(2903); + CyclicGroup group = new Zn(p); + int t = 10; + int n = 20; + random = new Random(); + verifiableSecretSharingArray = new VerifiableSecretSharing[tests]; + for (int i = 0; i < verifiableSecretSharingArray.length; i++){ + verifiableSecretSharingArray[i] = new VerifiableSecretSharing(group,t,n,group.sample(random),random); + } + } + + public void oneTest(VerifiableSecretSharing verifiableSecretSharing) throws Exception { + int n = verifiableSecretSharing.getN(); + BigInteger p = verifiableSecretSharing.getP(); + CyclicGroup group = verifiableSecretSharing.getGroup(); + BigInteger g = verifiableSecretSharing.getGenerator(); + Polynomial.Point[] shares = new Polynomial.Point[n]; + BigInteger[] commitments = verifiableSecretSharing.getCommitments(); + BigInteger[] verifications = new BigInteger[n]; + for (int i = 1 ; i <= shares.length; i ++){ + shares[i - 1] = verifiableSecretSharing.getShare(i); + verifications[i - 1] = VerifiableSecretSharing.verify(i,commitments,group); + } + BigInteger expected; + for (int i = 0 ; i < shares.length ; i++){ + expected = group.multiply(g,shares[i].y).mod(p); // problem with Zn, multiplication doesn't mod n as required + assert (expected.equals(verifications[i])); + } + + } + + @Test + public void secretSharingTest() throws Exception { + for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){ + oneTest(verifiableSecretSharingArray[i]); + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1360c1c..306cc66 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Jan 27 00:30:26 IST 2016 +#Fri Jan 29 21:00:29 IST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 635165ef8ef65c09c154fbffee97ee49cc1856f3 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 5 Feb 2016 13:30:16 +0200 Subject: [PATCH 013/106] sketch of JointFeldmanProtocol --- .../ShamirSecretSharing/Polynomial.java | 12 ++ .../ShamirSecretSharing/SecretSharing.java | 59 +++++---- .../VerifiableSecretSharing.java | 55 +++++--- .../main/java/JointFeldmanProtocol/DKG.java | 123 ++++++++++++++++++ .../java/JointFeldmanProtocol/Network.java | 27 ++++ .../PolynomialTests/Utils.java | 2 +- .../VerifiableSecretSharingTest.java | 22 ++-- 7 files changed, 242 insertions(+), 58 deletions(-) create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java index ac340b7..e285e01 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java @@ -186,6 +186,18 @@ public class Polynomial implements Comparable { this.y = polynomial.image(x); } + /** + * constructor + * @param x + * @param p + * @param polynomial y = polynomial.image(x) % q + * + */ + public Point(BigInteger x, Polynomial polynomial,BigInteger p) { + this.x = x; + this.y = polynomial.image(x); + } + /** * copy constructor * @param point diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index f5629d4..4a90ac7 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -9,59 +9,53 @@ import java.util.Random; * an implementation of Shamire's secret sharing scheme */ public class SecretSharing { - protected final int t; - protected final int n; + private final int t; + private final int n; + private final BigInteger q; - - protected final BigInteger p; - protected final Polynomial polynomial; + private final Polynomial polynomial; /** * constructor - * @param p prime + * @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 s secret, chosen from Zp + * @param x secret, chosen from Zq * @param random use for generate random polynomial */ - public SecretSharing(BigInteger p, int t, int n, BigInteger s, Random random) { - this.p = p; + public SecretSharing(int t, int n, BigInteger x, Random random,BigInteger q) { + this.q = q; this.t = t; this.n = n; - this.polynomial = generateRandomPolynomial(s,random); + this.polynomial = generateRandomPolynomial(x,random); } /** - * @param s + * @param x * @param random - * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests polynomial of degree t ,such that - * 1. polynomial(0) = s - * 2. polynomial coefficients randomly chosen from Zp (except of coefficients[0] = s) + * @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 s, Random random) { + private Polynomial generateRandomPolynomial(BigInteger x, Random random) { BigInteger[] coefficients = new BigInteger[t + 1]; - coefficients[0] = s; - int bits = p.bitLength(); + coefficients[0] = x.mod(q); + int bits = q.bitLength(); for (int i = 1 ; i <= t; i++ ){ - coefficients[i] = new BigInteger(bits,random).mod(p); + coefficients[i] = new BigInteger(bits,random).mod(q); } return new Polynomial(coefficients); } - //ToDo make it safe : permission to call this func /** * @param i in range of [1,...n] * - * @return polynomial.image(i) - * - * @throws Exception i out of range + * @return polynomial.image(i)%q */ - public Polynomial.Point getShare(int i) throws Exception { - if(i < 1 || i > n){ - throw new Exception(); - } - return new Polynomial.Point(BigInteger.valueOf(i), polynomial); + protected Polynomial.Point getShare(int i){ + assert (i > 0 && i <= n); + return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); } /** @@ -78,7 +72,7 @@ public class SecretSharing { * getter * @return threshold */ - public int getThreshold() { + public int getT() { return t; } @@ -94,7 +88,12 @@ public class SecretSharing { * getter * @return the prime was given in the constructor */ - public BigInteger getP() { - return p; + public BigInteger getQ() { + return q; + } + + protected Polynomial getPolynomial() { + + return polynomial; } } diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 082177f..e8d5c98 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -1,41 +1,55 @@ package FeldmanVerifiableSecretSharing; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import FeldmanVerifiableSecretSharing.ShamirSecretSharing.SecretSharing; import org.bouncycastle.util.Arrays; import org.factcenter.qilin.primitives.CyclicGroup; +import org.factcenter.qilin.primitives.concrete.Zpstar; 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 extends SecretSharing { - - private final CyclicGroup group; + private final Zpstar zpstar; private final BigInteger g; // public generator of group private final BigInteger[] commitments; - + private final BigInteger y; // y = g ^ x /** - * @param group a cyclic group of prime order p. - * it must be chosen such that computing discrete logarithms is hard in this group. + * @param p a large prime + * @param q a large prime dividing p - 1. + * @param g a generator of cyclic group of order q. + * the generated group is a subgroup of Zp*. + * it must be chosen such that computing discrete logarithms is hard in this group. */ - public VerifiableSecretSharing(CyclicGroup group, int t, int n, BigInteger s, Random random) { - super(group.orderUpperBound(), t, n, s, random); - this.group = group; - this.g = group.getGenerator(); + public VerifiableSecretSharing(int t, int n, BigInteger x, Random random,BigInteger p,BigInteger q,BigInteger g) { + super(t, n, x, random,q); + this.g = g; + this.zpstar = new Zpstar(p); + assert (zpstar.contains(g)); + assert (p.subtract(BigInteger.ONE).mod(q).equals(BigInteger.ZERO)); // assert p - 1 % q == 0 this.commitments = generateCommitments(); + this.y = zpstar.multiply(g,x); } /** * @return commitments[i] = g ^ polynomial.coefficients[i] */ private BigInteger[] generateCommitments() { + + Polynomial polynomial = getPolynomial(); BigInteger[] coefficients = polynomial.getCoefficients(); BigInteger[] commitments = new BigInteger[coefficients.length]; for (int i = 0 ; i < commitments.length;i++){ - commitments[i] = group.multiply(g,coefficients[i]); + commitments[i] = zpstar.multiply(g,coefficients[i]); } return commitments; } @@ -43,16 +57,16 @@ public class VerifiableSecretSharing extends SecretSharing { /** * @param i share holder id * @param commitments - * @param group + * @param zpstar * * @return product of commitments[j] ^ (i ^ j) == g ^ polynomial(i) */ - public static BigInteger verify(int i,BigInteger[] commitments,CyclicGroup group) { - BigInteger v = group.zero(); + public static BigInteger verify(int i,BigInteger[] commitments,Zpstar zpstar) { + BigInteger v = zpstar.zero(); BigInteger power = BigInteger.ONE; BigInteger I = BigInteger.valueOf(i); for (int j = 0 ; j < commitments.length ; j ++){ - v = group.add(v,group.multiply(commitments[j],power)); + v = zpstar.add(v,zpstar.multiply(commitments[j],power)); power = power.multiply(I); } return v; @@ -75,12 +89,19 @@ public class VerifiableSecretSharing extends SecretSharing { return Arrays.clone(commitments); } + /** + * getter + * @return zpstar + */ + public Zpstar getZpstar(){ + return zpstar; + } /** * getter - * @return the cyclic group was given in the constructor + * @return public value of this */ - public CyclicGroup getGroup() { - return group; + public BigInteger getY(){ + return y; } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java new file mode 100644 index 0000000..6962d29 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java @@ -0,0 +1,123 @@ +package JointFeldmanProtocol; + +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import org.bouncycastle.util.Arrays; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 2/5/2016. + * + * an implementation of a version of Pedersen's distributed key generation protocol + */ +public class DKG extends VerifiableSecretSharing{ + + private Network.User user; + private Polynomial.Point[][] shares; + private BigInteger[][] commitmentsArray; + private Set QUAL; + + private BigInteger x; + private BigInteger y; + private BigInteger[] commitments; + + public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g) { + super(t, n, x, random, p, q, g); + } + + private void stage1(){ + int n = getN(); + int i = user.getID(); + BigInteger[] commitments = super.getCommitments(); + System.arraycopy(commitments, 0, commitmentsArray[i - 1], 0, commitmentsArray[i - 1].length); + + Network.Message message = null; + for (int j = 1; j <= commitmentsArray[i - 1].length; j ++){ + //message = new Message(Type.Commitment, Shares[i - 1][j - 1]) + user.sendBroadcast(message); + } + + + for (int j = 1; j <= shares[i - 1].length; j ++){ + shares[i - 1][j - 1] = getShare(j); + } + for (int j = 1; j <= n ; j++ ){ + if(j != i){ + //message = new Message(Type.Share, Shares[i - 1][j - 1]) + user.send(j,message); + } + } + //Todo receive messages + } + + private void stage2(){ + int n = getN(); + BigInteger g = getGenerator(); + Zpstar zpstar = getZpstar(); + int i = user.getID(); + Network.Message message = null; + for (int j = 1; j <= n ; j++ ){ + if(zpstar.multiply(g,shares[i - 1][j - 1].y).equals(verify(j,commitmentsArray[j],zpstar))){ + QUAL.add(j); + }else{ + //message = new Message(Type.Complaint, j) + user.sendBroadcast(message); + } + } + + } + + private void stage3(){ + + //Todo receive something private from each complaint + send what necessary + + + } + + private void stage4(){ + Network.Message message = null; + // message = new Message(Type.Y, super.getY()) + user.sendBroadcast(message); + Zpstar zpstar = getZpstar(); + BigInteger y = zpstar.zero(); + for (Network.User user:this.user.getNetwork()) { + //Todo receive yi from all i in QUAL and calc y total + } + int t = getT(); + this.commitments = new BigInteger[t]; + BigInteger commitment; + for (int k = 1; k <= t ; k++){ + commitment = zpstar.zero(); + for (int i : QUAL) { + commitment = zpstar.add(commitment,commitmentsArray[i - 1][k - 1]); + } + commitments[k - 1] = commitment; + } + + int j = user.getID(); + BigInteger x = BigInteger.ZERO; + for (int i : QUAL) { + x = x.add(shares[i][j].y); + } + this.x = x.mod(getQ()); + } + + @Override + public BigInteger getY() { + return y; + } + + @Override + public BigInteger[] getCommitments() { + return Arrays.clone(commitments); + } + + @Override + protected Polynomial.Point getShare(int i) { + return null; + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java new file mode 100644 index 0000000..46c1d44 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java @@ -0,0 +1,27 @@ +package JointFeldmanProtocol; + +/** + * Created by Tzlil on 2/5/2016. + */ +public interface Network extends Iterable{ + + User connect(); + + interface User{ + int getID(); + void send(int userID,Message message); + void sendBroadcast(Message message); + void receive(int userID,Message message); + void receiveBroadcast(Message message); + Network getNetwork(); + } + + interface Message{ + enum Type { + Commitment, Share, Complaint, Y + } + + Type getType(); + + } +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java index b43869d..67bd51c 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java @@ -14,7 +14,7 @@ public class Utils { BigInteger[] coefficients = new BigInteger[degree + 1]; for (int i = 0 ; i <= degree; i++ ){ - coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... p-1] + coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... q-1] } return new Polynomial(coefficients); } diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index 8846cd9..ec58262 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -1,15 +1,13 @@ package FeldmanVerifiableSecretSharing; import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.SecretSharing; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; +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.List; import java.util.Random; /** @@ -25,31 +23,34 @@ public class VerifiableSecretSharingTest { @Before public void settings(){ BigInteger p = BigInteger.valueOf(2903); - CyclicGroup group = new Zn(p); - int t = 10; + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + + int t = 8; int n = 20; random = new Random(); + BigInteger g = null; //Todo verifiableSecretSharingArray = new VerifiableSecretSharing[tests]; for (int i = 0; i < verifiableSecretSharingArray.length; i++){ - verifiableSecretSharingArray[i] = new VerifiableSecretSharing(group,t,n,group.sample(random),random); + verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n + ,new BigInteger(q.bitLength(),random).mod(q),random,p,q,g); } } public void oneTest(VerifiableSecretSharing verifiableSecretSharing) throws Exception { int n = verifiableSecretSharing.getN(); - BigInteger p = verifiableSecretSharing.getP(); - CyclicGroup group = verifiableSecretSharing.getGroup(); + BigInteger p = verifiableSecretSharing.getQ(); + Zpstar zpstar = new Zpstar(p); BigInteger g = verifiableSecretSharing.getGenerator(); Polynomial.Point[] shares = new Polynomial.Point[n]; BigInteger[] commitments = verifiableSecretSharing.getCommitments(); BigInteger[] verifications = new BigInteger[n]; for (int i = 1 ; i <= shares.length; i ++){ shares[i - 1] = verifiableSecretSharing.getShare(i); - verifications[i - 1] = VerifiableSecretSharing.verify(i,commitments,group); + verifications[i - 1] = VerifiableSecretSharing.verify(i,commitments,zpstar); } BigInteger expected; for (int i = 0 ; i < shares.length ; i++){ - expected = group.multiply(g,shares[i].y).mod(p); // problem with Zn, multiplication doesn't mod n as required + expected = zpstar.multiply(g,shares[i].y); assert (expected.equals(verifications[i])); } @@ -59,6 +60,7 @@ public class VerifiableSecretSharingTest { public void secretSharingTest() throws Exception { for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){ oneTest(verifiableSecretSharingArray[i]); + } } } From 0a8d4abe72d539de44c1fbfaa2e92e9761c62b99 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 5 Feb 2016 13:36:55 +0200 Subject: [PATCH 014/106] sketch of JointFeldmanProtocol --- .../ShamirSecretSharing/SecretSharing.java | 7 +++++++ .../ShamirSecretSharing/SecretSharingTest.java | 4 ++-- .../VerifiableSecretSharingTest.java | 7 +++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index 4a90ac7..0559a7c 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -58,6 +58,13 @@ public class SecretSharing { return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); } + /** + * use for test only + */ + public Polynomial.Point getShareForTest(int i){ + return getShare(i); + } + /** * @param shares - subset of the original shares * diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java index d5f8842..bc96f7f 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java @@ -33,12 +33,12 @@ public class SecretSharingTest { secrets = new BigInteger[tests]; for (int i = 0; i < secretSharingArray.length; i++){ secrets[i] = group.sample(random); - secretSharingArray[i] = new SecretSharing(p,t,n,secrets[i],random); + secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,p); } } public void oneTest(SecretSharing secretSharing, BigInteger secret) throws Exception { - int t = secretSharing.getThreshold(); + int t = secretSharing.getT(); int n = secretSharing.getN(); Polynomial.Point[] shares = new Polynomial.Point[t + 1]; List indexes = new ArrayList(n); diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index ec58262..cb18f3f 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -20,7 +20,7 @@ public class VerifiableSecretSharingTest { int tests = 1 << 10; Random random; - @Before + //@Before public void settings(){ BigInteger p = BigInteger.valueOf(2903); BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); @@ -45,7 +45,7 @@ public class VerifiableSecretSharingTest { BigInteger[] commitments = verifiableSecretSharing.getCommitments(); BigInteger[] verifications = new BigInteger[n]; for (int i = 1 ; i <= shares.length; i ++){ - shares[i - 1] = verifiableSecretSharing.getShare(i); + shares[i - 1] = verifiableSecretSharing.getShareForTest(i); verifications[i - 1] = VerifiableSecretSharing.verify(i,commitments,zpstar); } BigInteger expected; @@ -56,11 +56,10 @@ public class VerifiableSecretSharingTest { } - @Test + //@Test public void secretSharingTest() throws Exception { for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){ oneTest(verifiableSecretSharingArray[i]); - } } } From 91dd19ead292b88992041541677619da7f753acc Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Sun, 7 Feb 2016 14:38:47 +0200 Subject: [PATCH 015/106] message handler --- .../main/java/JointFeldmanProtocol/DKG.java | 119 +++++++++++--- .../java/JointFeldmanProtocol/Network.java | 148 ++++++++++++++++-- .../VerifiableSecretSharingTest.java | 20 +-- 3 files changed, 238 insertions(+), 49 deletions(-) diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java index 6962d29..49a6f17 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java @@ -6,6 +6,7 @@ import org.bouncycastle.util.Arrays; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; +import java.util.HashSet; import java.util.Random; import java.util.Set; @@ -14,44 +15,55 @@ import java.util.Set; * * an implementation of a version of Pedersen's distributed key generation protocol */ -public class DKG extends VerifiableSecretSharing{ +public class DKG extends VerifiableSecretSharing implements Runnable{ private Network.User user; - private Polynomial.Point[][] shares; + private Handler handler; + private Polynomial.Point[] shares; private BigInteger[][] commitmentsArray; + private BigInteger[] ys; private Set QUAL; private BigInteger x; private BigInteger y; private BigInteger[] commitments; - public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g) { + public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g,Network network) { super(t, n, x, random, p, q, g); + this.commitmentsArray = new BigInteger[n][t + 1]; + this.shares = new Polynomial.Point[n]; + this.handler = new Handler(); + this.user = network.connect(handler); } + private void stage1(){ int n = getN(); + int t = getT(); int i = user.getID(); BigInteger[] commitments = super.getCommitments(); System.arraycopy(commitments, 0, commitmentsArray[i - 1], 0, commitmentsArray[i - 1].length); - Network.Message message = null; + Network.CommitmentMessage commitment; for (int j = 1; j <= commitmentsArray[i - 1].length; j ++){ - //message = new Message(Type.Commitment, Shares[i - 1][j - 1]) - user.sendBroadcast(message); + commitment = new Network.CommitmentMessage(j,commitmentsArray[i - 1][j - 1]); + user.broadcast(commitment); } - - for (int j = 1; j <= shares[i - 1].length; j ++){ - shares[i - 1][j - 1] = getShare(j); - } + Network.SecretMessage secret; for (int j = 1; j <= n ; j++ ){ if(j != i){ - //message = new Message(Type.Share, Shares[i - 1][j - 1]) - user.send(j,message); + secret = new Network.SecretMessage(getShare(j)); + user.send(j,secret); + } + } + while (handler.secretsCounter < n - 1 || handler.commitmentsCounter < (n - 1) * (t + 1)){ + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing } } - //Todo receive messages } private void stage2(){ @@ -59,35 +71,40 @@ public class DKG extends VerifiableSecretSharing{ BigInteger g = getGenerator(); Zpstar zpstar = getZpstar(); int i = user.getID(); + QUAL = new HashSet(); Network.Message message = null; for (int j = 1; j <= n ; j++ ){ - if(zpstar.multiply(g,shares[i - 1][j - 1].y).equals(verify(j,commitmentsArray[j],zpstar))){ + if(zpstar.multiply(g,shares[j - 1].y).equals(verify(j,commitmentsArray[j],zpstar))){ QUAL.add(j); }else{ //message = new Message(Type.Complaint, j) - user.sendBroadcast(message); + user.broadcast(message); } } - + //sending y after Complaints + Network.YMessage yMessage = new Network.YMessage(super.getY()); + user.broadcast(yMessage); } private void stage3(){ - + int n = getN(); + while (handler.ysCounter < n - 1 ){ + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing + } + } //Todo receive something private from each complaint + send what necessary - - } private void stage4(){ - Network.Message message = null; - // message = new Message(Type.Y, super.getY()) - user.sendBroadcast(message); + int t = getT(); Zpstar zpstar = getZpstar(); BigInteger y = zpstar.zero(); - for (Network.User user:this.user.getNetwork()) { - //Todo receive yi from all i in QUAL and calc y total + for (int i : QUAL) { + y = zpstar.add(y , ys[i - 1]); } - int t = getT(); this.commitments = new BigInteger[t]; BigInteger commitment; for (int k = 1; k <= t ; k++){ @@ -101,7 +118,7 @@ public class DKG extends VerifiableSecretSharing{ int j = user.getID(); BigInteger x = BigInteger.ZERO; for (int i : QUAL) { - x = x.add(shares[i][j].y); + x = x.add(shares[i - 1].y); } this.x = x.mod(getQ()); } @@ -120,4 +137,54 @@ public class DKG extends VerifiableSecretSharing{ protected Polynomial.Point getShare(int i) { return null; } + + @Override + public void run() { + stage1(); + stage2(); + stage3(); + stage4(); + } + + private class Handler implements Network.MailHandler { + + final int id; + int secretsCounter; + int commitmentsCounter; + int ysCounter; + + private Handler() { + this.id = user.getID(); + this.secretsCounter = 0; + this.commitmentsCounter = 0; + this.ysCounter = 0; + } + + @Override + public void handel(Network.Mail mail) { + if(mail.isPrivate){ + if(mail.message instanceof Network.SecretMessage){ + Polynomial.Point secret = ((Network.SecretMessage)mail.message).secret; + if(shares[id - 1] == null) { + shares[id - 1] = secret; + secretsCounter++; + } + } + }else{ + if(mail.message instanceof Network.CommitmentMessage){ + Network.CommitmentMessage commitmentMessage = (Network.CommitmentMessage)mail.message; + if(commitmentsArray[mail.senderID - 1][commitmentMessage.k] == null) { + commitmentsArray[mail.senderID - 1][commitmentMessage.k] = commitmentMessage.commitment; + commitmentsCounter++; + } + }else if(mail.message instanceof Network.YMessage){ + BigInteger y = ((Network.YMessage)mail.message).y; + if(ys[mail.senderID - 1] == null){ + ys[mail.senderID - 1] = y; + ysCounter ++; + } + } + } + } + } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java index 46c1d44..8468d2d 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java @@ -1,27 +1,147 @@ package JointFeldmanProtocol; +import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; + +import java.lang.reflect.Type; +import java.math.BigInteger; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; /** - * Created by Tzlil on 2/5/2016. + * Created by Tzlil on 2/7/2016. */ -public interface Network extends Iterable{ +public class Network { - User connect(); + private final User[] users; + private final int n; + private final Queue availableIDs; - interface User{ - int getID(); - void send(int userID,Message message); - void sendBroadcast(Message message); - void receive(int userID,Message message); - void receiveBroadcast(Message message); - Network getNetwork(); + + public Network(int n) { + this.n = n; + this.users = new User[n]; + this.availableIDs = new ArrayBlockingQueue(n); + for (int id = 1; id <= n; id++){ + availableIDs.add(id); + } } - interface Message{ - enum Type { - Commitment, Share, Complaint, Y + public User connect(MailHandler messageHandler){ + Integer id = availableIDs.poll(); + if (id == null) + return null; + return new User(id,messageHandler); + } + + private boolean sendMessage(User sender,int destination,Message message){ + if(destination < 1 || destination > n) + return false; + User user = users[destination - 1]; + if (user == null) + return false; + return user.mailbox.add(new Mail(sender.ID,false,message)); + } + + private void sendBroadcast(User sender,Message message){ + User user; + int ID = sender.ID; + for (int i = 0 ; i < n ; i++){ + if (i + 1 == ID) { + continue; + } + user = users[i]; + user.mailbox.add(new Mail(ID,true,message)); + } + } + + public class User{ + private final MailHandler messageHandler; + private final Queue mailbox; + private final int ID; + + public User(int ID, MailHandler messageHandler) { + this.mailbox = new ArrayBlockingQueue(n*n); + this.ID = ID; + this.messageHandler = messageHandler; + Thread thread = new Thread(new Receiver()); + thread.run(); + } + + + public boolean send(int id, Message message){ + return sendMessage(this,id,message); + } + public void broadcast(Message message){ + sendBroadcast(this,message); + } + + public int getID() { + return ID; + } + + private class Receiver implements Runnable{ + @Override + public void run() { + while (true){ + if (!mailbox.isEmpty()){ + messageHandler.handel(mailbox.poll()); + }else{ + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing + } + } + } + } } - Type getType(); } + + public class Mail{ + public final int senderID; + public final boolean isPrivate; + public final Message message; + + private Mail(int senderID, boolean isPrivate, Message message) { + this.senderID = senderID; + this.isPrivate = isPrivate; + this.message = message; + } + } + + public static abstract class Message{ + + } + public static class CommitmentMessage extends Message{ + public final int k; + public final BigInteger commitment; + + + public CommitmentMessage(int k, BigInteger commitment) { + this.k = k; + this.commitment = commitment; + } + } + + public static class YMessage extends Message{ + + public final BigInteger y; + + public YMessage(BigInteger y) { + this.y = y; + } + } + + public static class SecretMessage extends Message{ + public final Polynomial.Point secret; + + public SecretMessage(Polynomial.Point secret) { + this.secret = secret; + } + } + + public interface MailHandler { + public void handel(Mail mail); + } } diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index cb18f3f..8a4f15d 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -1,8 +1,6 @@ package FeldmanVerifiableSecretSharing; import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; -import org.factcenter.qilin.primitives.CyclicGroup; -import org.factcenter.qilin.primitives.concrete.Zn; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; import org.junit.Test; @@ -20,15 +18,20 @@ public class VerifiableSecretSharingTest { int tests = 1 << 10; Random random; - //@Before + @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; - random = new Random(); - BigInteger g = null; //Todo + verifiableSecretSharingArray = new VerifiableSecretSharing[tests]; for (int i = 0; i < verifiableSecretSharingArray.length; i++){ verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n @@ -38,8 +41,7 @@ public class VerifiableSecretSharingTest { public void oneTest(VerifiableSecretSharing verifiableSecretSharing) throws Exception { int n = verifiableSecretSharing.getN(); - BigInteger p = verifiableSecretSharing.getQ(); - Zpstar zpstar = new Zpstar(p); + Zpstar zpstar = verifiableSecretSharing.getZpstar(); BigInteger g = verifiableSecretSharing.getGenerator(); Polynomial.Point[] shares = new Polynomial.Point[n]; BigInteger[] commitments = verifiableSecretSharing.getCommitments(); @@ -56,7 +58,7 @@ public class VerifiableSecretSharingTest { } - //@Test + @Test public void secretSharingTest() throws Exception { for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){ oneTest(verifiableSecretSharingArray[i]); From 8288b07d8001ca6748562f187b6f9c5905cab539 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Mon, 8 Feb 2016 15:20:43 +0200 Subject: [PATCH 016/106] joint feldman with protos --- .../ShamirSecretSharing/Polynomial.java | 23 +- .../ShamirSecretSharing/SecretSharing.java | 6 +- .../VerifiableSecretSharing.java | 34 +-- .../main/java/JointFeldmanProtocol/DKG.java | 262 ++++++++++++++---- .../java/JointFeldmanProtocol/Network.java | 90 +++--- .../src/main/proto/meerkat/DKGMessages.proto | 40 +++ 6 files changed, 310 insertions(+), 145 deletions(-) create mode 100644 meerkat-common/src/main/proto/meerkat/DKGMessages.proto diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java index e285e01..30a56ed 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java @@ -1,7 +1,8 @@ package FeldmanVerifiableSecretSharing.ShamirSecretSharing; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; import org.bouncycastle.util.Arrays; - import java.math.BigInteger; /** @@ -172,7 +173,7 @@ public class Polynomial implements Comparable { * inner class * container for (x,y) x from range and y from image of polynomial */ - public static class Point{ + public static class Point implements java.io.Serializable { public final BigInteger x; public final BigInteger y; @@ -199,13 +200,21 @@ public class Polynomial implements Comparable { } /** - * copy constructor - * @param point + * constructor - restore point from message + * @param pointMessage */ - public Point(Point point) { - this.x = point.x; - this.y = point.y; + public Point(DKGMessages.SecretMessage.Point pointMessage) { + this.x = new BigInteger(pointMessage.getX().toByteArray()); + this.y = new BigInteger(pointMessage.getY().toByteArray()); } + + public DKGMessages.SecretMessage.Point asMessage(){ + return DKGMessages.SecretMessage.Point.newBuilder() + .setX(ByteString.copyFrom(x.toByteArray())) + .setY(ByteString.copyFrom(y.toByteArray())) + .build(); + } + } } diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index 0559a7c..ebed7a2 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -9,9 +9,9 @@ import java.util.Random; * an implementation of Shamire's secret sharing scheme */ public class SecretSharing { - private final int t; - private final int n; - private final BigInteger q; + protected final int t; + protected final int n; + protected final BigInteger q; private final Polynomial polynomial; diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index e8d5c98..eb3dc07 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -18,10 +18,10 @@ import java.util.Random; * */ public class VerifiableSecretSharing extends SecretSharing { - private final Zpstar zpstar; - private final BigInteger g; // public generator of group - private final BigInteger[] commitments; + protected final Zpstar zpstar; + protected final BigInteger g; // public generator of group private final BigInteger y; // y = g ^ x + private final BigInteger[] commitments; /** * @param p a large prime @@ -55,19 +55,19 @@ public class VerifiableSecretSharing extends SecretSharing { } /** - * @param i share holder id + * @param j share holder id * @param commitments * @param zpstar * * @return product of commitments[j] ^ (i ^ j) == g ^ polynomial(i) */ - public static BigInteger verify(int i,BigInteger[] commitments,Zpstar zpstar) { + public static BigInteger verify(int j,BigInteger[] commitments,Zpstar zpstar) { BigInteger v = zpstar.zero(); BigInteger power = BigInteger.ONE; - BigInteger I = BigInteger.valueOf(i); - for (int j = 0 ; j < commitments.length ; j ++){ - v = zpstar.add(v,zpstar.multiply(commitments[j],power)); - power = power.multiply(I); + BigInteger J = BigInteger.valueOf(j); + for (int k = 0 ; k < commitments.length ; k ++){ + v = zpstar.add(v,zpstar.multiply(commitments[k],power)); + power = power.multiply(J); } return v; } @@ -81,14 +81,6 @@ public class VerifiableSecretSharing extends SecretSharing { return g; } - /** - * getter - * @return copy of commitments - */ - public BigInteger[] getCommitments() { - return Arrays.clone(commitments); - } - /** * getter * @return zpstar @@ -104,4 +96,12 @@ public class VerifiableSecretSharing extends SecretSharing { public BigInteger getY(){ return y; } + + /** + * getter + * @return copy of commitments + */ + public BigInteger[] getCommitments() { + return Arrays.clone(commitments); + } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java index 49a6f17..dcd12fa 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java @@ -2,8 +2,10 @@ package JointFeldmanProtocol; import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import org.bouncycastle.util.Arrays; -import org.factcenter.qilin.primitives.concrete.Zpstar; +import meerkat.protobuf.DKGMessages.*; import java.math.BigInteger; import java.util.HashSet; @@ -18,10 +20,12 @@ import java.util.Set; public class DKG extends VerifiableSecretSharing implements Runnable{ private Network.User user; - private Handler handler; + private Network.MailHandler handler; private Polynomial.Point[] shares; + private Polynomial.Point[] myshares; private BigInteger[][] commitmentsArray; private BigInteger[] ys; + final ComplainState[][] complainStates; private Set QUAL; private BigInteger x; @@ -30,34 +34,47 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g,Network network) { super(t, n, x, random, p, q, g); + this.commitmentsArray = new BigInteger[n][t + 1]; this.shares = new Polynomial.Point[n]; + this.myshares = new Polynomial.Point[n]; this.handler = new Handler(); this.user = network.connect(handler); + this.complainStates = new ComplainState[n][n]; + + for (int i = 0; i < n; i ++){ + for (int j = 0 ; j < n ; j ++) + complainStates[i][j] = ComplainState.Non; + } + } private void stage1(){ - int n = getN(); - int t = getT(); int i = user.getID(); BigInteger[] commitments = super.getCommitments(); System.arraycopy(commitments, 0, commitmentsArray[i - 1], 0, commitmentsArray[i - 1].length); - Network.CommitmentMessage commitment; - for (int j = 1; j <= commitmentsArray[i - 1].length; j ++){ - commitment = new Network.CommitmentMessage(j,commitmentsArray[i - 1][j - 1]); - user.broadcast(commitment); + CommitmentMessage commitment; + for (int k = 1; k <= commitmentsArray[i - 1].length; k ++){ + commitment = CommitmentMessage.newBuilder() + .setK(k) + .setCommitment(ByteString.copyFrom(commitmentsArray[i - 1][k - 1].toByteArray())) + .build(); + user.broadcast(Mail.Type.COMMITMENT,commitment); } - Network.SecretMessage secret; + SecretMessage secret; for (int j = 1; j <= n ; j++ ){ if(j != i){ - secret = new Network.SecretMessage(getShare(j)); - user.send(j,secret); + myshares[j - 1] = super.getShare(j); + secret = SecretMessage.newBuilder() + .setSecret(myshares[j - 1].asMessage()) + .build(); + user.send(j, Mail.Type.SECRET,secret); } } - while (handler.secretsCounter < n - 1 || handler.commitmentsCounter < (n - 1) * (t + 1)){ + while (!isStage1Complete()){ try { Thread.sleep(30); } catch (InterruptedException e) { @@ -66,41 +83,112 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ } } + private boolean isStage1Complete(){ + int id = user.getID(); + for (int j = 1 ; j <= n ; j++){ + if(id != j && shares[j - 1] == null) + return false; + } + + for (int i = 0; i < commitmentsArray.length; i++){ + for (int j = 0; j < commitmentsArray[i].length; j++){ + if(commitmentsArray[i][j] == null) + return false; + } + } + return true; + } + + private boolean isValidSecret(Polynomial.Point secret, int i){ + int j = secret.x.intValue(); + return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i],zpstar)); + } + private void stage2(){ - int n = getN(); - BigInteger g = getGenerator(); - Zpstar zpstar = getZpstar(); - int i = user.getID(); + int j = user.getID(); QUAL = new HashSet(); - Network.Message message = null; - for (int j = 1; j <= n ; j++ ){ - if(zpstar.multiply(g,shares[j - 1].y).equals(verify(j,commitmentsArray[j],zpstar))){ - QUAL.add(j); + ComplaintMessage complaint; + for (int i = 1; i <= n ; i++ ){ + if(isValidSecret(shares[i - 1],j)) { + QUAL.add(i); }else{ //message = new Message(Type.Complaint, j) - user.broadcast(message); + complaint = ComplaintMessage.newBuilder() + .setId(i) + .build(); + user.broadcast(Mail.Type.COMPLAINT,complaint); + complainStates[j - 1][i - 1] = ComplainState.Waiting; } } //sending y after Complaints - Network.YMessage yMessage = new Network.YMessage(super.getY()); - user.broadcast(yMessage); - } + YMessage yMessage = YMessage.newBuilder() + .setY(ByteString.copyFrom(super.getY().toByteArray())) + .build(); + user.broadcast(Mail.Type.Y,yMessage); - private void stage3(){ - int n = getN(); - while (handler.ysCounter < n - 1 ){ + while (!isStage2Complete()){ try { Thread.sleep(30); } catch (InterruptedException e) { // do nothing } } - //Todo receive something private from each complaint + send what necessary + } + + private boolean isStage2Complete() { + int id = user.getID(); + for (int j = 1; j <= n ; j++) { + if (id != j && ys[j - 1] == null) + return false; + } + for (int i = 0; i < complainStates.length;i++){ + for (int j =0 ; j < complainStates[i].length;j++){ + switch (complainStates[i][j]){ + case Waiting: + return false; + default: + break; + } + } + } + return true; + } + + private void stage3(){ + for (int i = 0; i < complainStates.length;i++){ + ComplainState state = ComplainState.Non; + for (int j = 0 ; j < complainStates[i].length;j++){ + switch (complainStates[i][j]){ + case Disqualified: + state = ComplainState.Disqualified; + break; + case NonDisqualified: + if(state == ComplainState.Non){ + state = ComplainState.NonDisqualified; + } + break; + default: + break; + } + } + switch (state){ + case Disqualified: + if(QUAL.contains(i + 1)){ + QUAL.remove(i + 1); + } + break; + case NonDisqualified: + if (!QUAL.contains(i + 1)){ + QUAL.add(i + 1); + } + break; + default: + break; + } + } } private void stage4(){ - int t = getT(); - Zpstar zpstar = getZpstar(); BigInteger y = zpstar.zero(); for (int i : QUAL) { y = zpstar.add(y , ys[i - 1]); @@ -120,7 +208,7 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ for (int i : QUAL) { x = x.add(shares[i - 1].y); } - this.x = x.mod(getQ()); + this.x = x.mod(q); } @Override @@ -146,45 +234,101 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ stage4(); } + private enum ComplainState{ + Non, Waiting,Disqualified,NonDisqualified + } + private class Handler implements Network.MailHandler { final int id; - int secretsCounter; - int commitmentsCounter; - int ysCounter; private Handler() { this.id = user.getID(); - this.secretsCounter = 0; - this.commitmentsCounter = 0; - this.ysCounter = 0; } - @Override - public void handel(Network.Mail mail) { - if(mail.isPrivate){ - if(mail.message instanceof Network.SecretMessage){ - Polynomial.Point secret = ((Network.SecretMessage)mail.message).secret; - if(shares[id - 1] == null) { - shares[id - 1] = secret; - secretsCounter++; - } - } - }else{ - if(mail.message instanceof Network.CommitmentMessage){ - Network.CommitmentMessage commitmentMessage = (Network.CommitmentMessage)mail.message; - if(commitmentsArray[mail.senderID - 1][commitmentMessage.k] == null) { - commitmentsArray[mail.senderID - 1][commitmentMessage.k] = commitmentMessage.commitment; - commitmentsCounter++; - } - }else if(mail.message instanceof Network.YMessage){ - BigInteger y = ((Network.YMessage)mail.message).y; - if(ys[mail.senderID - 1] == null){ - ys[mail.senderID - 1] = y; - ysCounter ++; + void handelSecretMessage(Mail mail) throws InvalidProtocolBufferException { + if(shares[mail.getSender() - 1] == null) { + SecretMessage secretMessage = SecretMessage.parseFrom(mail.getMessage()); + Polynomial.Point secret = new Polynomial.Point(secretMessage.getSecret()); + if(mail.getIsPrivate()){ + shares[mail.getSender() - 1] = secret; + }else{ + int i = mail.getSender(); + int j = secret.x.intValue(); + switch (complainStates[i][j]){ + case Waiting: + if(isValidSecret(secret,i)){ + complainStates[i][j] = ComplainState.NonDisqualified; + }else{ + complainStates[i][j] = ComplainState.Disqualified; + } + break; + default: + break; } } } } + + void handelCommitmentMessage(Mail mail) throws InvalidProtocolBufferException { + if(!mail.getIsPrivate()) { //broadcast only + CommitmentMessage commitmentMessage = CommitmentMessage.parseFrom(mail.getMessage()); + if (commitmentsArray[mail.getSender() - 1][commitmentMessage.getK()] == null) { + BigInteger commitment = new BigInteger(commitmentMessage.getCommitment().toByteArray()); + commitmentsArray[mail.getSender() - 1][commitmentMessage.getK()] = commitment; + } + } + } + + void handelYMessage(Mail mail) throws InvalidProtocolBufferException { + if(!mail.getIsPrivate()) { //broadcast only + if (ys[mail.getSender() - 1] == null) { + YMessage yMessage = YMessage.parseFrom(mail.getMessage()); + BigInteger y = new BigInteger(yMessage.getY().toByteArray()); + ys[mail.getSender() - 1] = y; + } + } + } + + void handelComplaintMessage(Mail mail) throws InvalidProtocolBufferException { + if(!mail.getIsPrivate()) { //broadcast only + ComplaintMessage complaintMessage = ComplaintMessage.parseFrom(mail.getMessage()); + int i = complaintMessage.getId(); + int j = mail.getSender(); + if(i == id){ + user.broadcast(Mail.Type.SECRET,SecretMessage.newBuilder() + .setSecret(myshares[j].asMessage()) + .build()); + }else{ + switch (complainStates[i - 1][j - 1]){ + case Non: + complainStates[i - 1][j - 1] = ComplainState.Waiting; + break; + default: + break; + } + } + } + } + + @Override + public void handel(Mail mail) throws InvalidProtocolBufferException { + switch (mail.getType()){ + case SECRET: + handelSecretMessage(mail); + break; + case COMMITMENT: + handelCommitmentMessage(mail); + break; + case Y: + handelYMessage(mail); + break; + case COMPLAINT: + handelComplaintMessage(mail); + break; + default: + break; + } + } } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java index 8468d2d..3cc3c85 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java @@ -1,9 +1,8 @@ package JointFeldmanProtocol; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; - -import java.lang.reflect.Type; -import java.math.BigInteger; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages.*; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; /** @@ -32,24 +31,38 @@ public class Network { return new User(id,messageHandler); } - private boolean sendMessage(User sender,int destination,Message message){ + private boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ if(destination < 1 || destination > n) return false; User user = users[destination - 1]; if (user == null) return false; - return user.mailbox.add(new Mail(sender.ID,false,message)); + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(destination) + .setIsPrivate(true) + .setType(type) + .setMessage(message.toByteString()) + .build(); + return user.mailbox.add(mail); } - private void sendBroadcast(User sender,Message message){ + private void sendBroadcast(User sender,Mail.Type type,Message message){ User user; int ID = sender.ID; + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(0) + .setIsPrivate(false) + .setType(type) + .setMessage(message.toByteString()) + .build(); for (int i = 0 ; i < n ; i++){ if (i + 1 == ID) { continue; } user = users[i]; - user.mailbox.add(new Mail(ID,true,message)); + user.mailbox.add(mail); } } @@ -66,14 +79,12 @@ public class Network { thread.run(); } - - public boolean send(int id, Message message){ - return sendMessage(this,id,message); + public boolean send(int id, Mail.Type type,Message message){ + return sendMessage(this,id,type,message); } - public void broadcast(Message message){ - sendBroadcast(this,message); + public void broadcast(Mail.Type type,Message message){ + sendBroadcast(this,type,message); } - public int getID() { return ID; } @@ -83,7 +94,11 @@ public class Network { public void run() { while (true){ if (!mailbox.isEmpty()){ - messageHandler.handel(mailbox.poll()); + try { + messageHandler.handel(mailbox.poll()); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } }else{ try { Thread.sleep(30); @@ -98,50 +113,7 @@ public class Network { } - public class Mail{ - public final int senderID; - public final boolean isPrivate; - public final Message message; - - private Mail(int senderID, boolean isPrivate, Message message) { - this.senderID = senderID; - this.isPrivate = isPrivate; - this.message = message; - } - } - - public static abstract class Message{ - - } - public static class CommitmentMessage extends Message{ - public final int k; - public final BigInteger commitment; - - - public CommitmentMessage(int k, BigInteger commitment) { - this.k = k; - this.commitment = commitment; - } - } - - public static class YMessage extends Message{ - - public final BigInteger y; - - public YMessage(BigInteger y) { - this.y = y; - } - } - - public static class SecretMessage extends Message{ - public final Polynomial.Point secret; - - public SecretMessage(Polynomial.Point secret) { - this.secret = secret; - } - } - public interface MailHandler { - public void handel(Mail mail); + public void handel(Mail mail) throws InvalidProtocolBufferException; } } diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto new file mode 100644 index 0000000..e874f5a --- /dev/null +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package meerkat; + +option java_package = "meerkat.protobuf"; + +message Mail{ + enum Type { + SECRET = 0; + COMMITMENT = 1; + Y = 2; + COMPLAINT = 3; + } + int32 sender = 1; + int32 destination = 2; + bool isPrivate = 3; + Type type = 4; + bytes message = 5; +} + +message SecretMessage { + message Point{ + bytes x = 1; + bytes y = 2; + } + Point secret = 1; +} + +message CommitmentMessage{ + int32 k = 1; + bytes commitment = 2; +} + +message YMessage{ + bytes y = 1; +} + +message ComplaintMessage{ + int32 id = 1; +} \ No newline at end of file From a233f2f7139cb011b8a5607335af75e81af1a272 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 9 Feb 2016 20:37:57 +0200 Subject: [PATCH 017/106] joint feldman protocol with test --- .../ShamirSecretSharing/Polynomial.java | 10 + .../ShamirSecretSharing/SecretSharing.java | 2 +- .../main/java/JointFeldmanProtocol/DKG.java | 254 ++++++++++-------- .../java/JointFeldmanProtocol/Network.java | 17 +- .../PolynomialTests/InterpolationTest.java | 1 - .../java/JointFeldmanProtocol/DKGTest.java | 57 ++++ 6 files changed, 220 insertions(+), 121 deletions(-) create mode 100644 destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java index 30a56ed..2bdf2ad 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java @@ -208,6 +208,16 @@ public class Polynomial implements Comparable { this.y = new BigInteger(pointMessage.getY().toByteArray()); } + /** + * constructor + * @param x + * @param y + */ + public Point(BigInteger x,BigInteger y) { + this.x = x; + this.y = y; + } + public DKGMessages.SecretMessage.Point asMessage(){ return DKGMessages.SecretMessage.Point.newBuilder() .setX(ByteString.copyFrom(x.toByteArray())) diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index ebed7a2..9e3319d 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -53,7 +53,7 @@ public class SecretSharing { * * @return polynomial.image(i)%q */ - protected Polynomial.Point getShare(int i){ + protected final Polynomial.Point getShare(int i){ assert (i > 0 && i <= n); return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java index dcd12fa..2cbef48 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java @@ -11,6 +11,7 @@ import java.math.BigInteger; import java.util.HashSet; import java.util.Random; import java.util.Set; +import java.util.concurrent.Callable; /** * Created by Tzlil on 2/5/2016. @@ -19,28 +20,31 @@ import java.util.Set; */ public class DKG extends VerifiableSecretSharing implements Runnable{ - private Network.User user; - private Network.MailHandler handler; - private Polynomial.Point[] shares; - private Polynomial.Point[] myshares; - private BigInteger[][] commitmentsArray; - private BigInteger[] ys; - final ComplainState[][] complainStates; - private Set QUAL; + private final int id; + private final Network.User user; // send and receive messages throw network + + private final BigInteger[] ys; // container for y values that + private final Polynomial.Point[] shares; // shares[i] equivalent to Si,id in terms of the protocol + private final BigInteger[][] commitmentsArray; // commitmentsArray[i] equivalent to Ai in terms of the protocol + private final ComplainState[][] complainStates; // complainStates[i][j] == state of Pj's complaint against Pi + + private final Set QUAL; // set of all non-disqualified parties + private final BigInteger[] commitments; // public verification values + private Polynomial.Point share; // final share of the secrete + private BigInteger y; // final public value - private BigInteger x; - private BigInteger y; - private BigInteger[] commitments; public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g,Network network) { super(t, n, x, random, p, q, g); this.commitmentsArray = new BigInteger[n][t + 1]; this.shares = new Polynomial.Point[n]; - this.myshares = new Polynomial.Point[n]; - this.handler = new Handler(); - this.user = network.connect(handler); + this.user = network.connect(new Handler()); + this.id = user.getID(); this.complainStates = new ComplainState[n][n]; + this.QUAL = new HashSet(); + this.ys = new BigInteger[n]; + this.commitments = new BigInteger[t + 1]; for (int i = 0; i < n; i ++){ for (int j = 0 ; j < n ; j ++) @@ -49,44 +53,67 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ } + /** + * use for simulate real distributed protocol + */ + @Override + public void run() { + user.getReceiverThread().start(); + stage1(); + stage2(); + stage3(); + stage4(); + user.getReceiverThread().interrupt(); + } + /** + * 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. + */ private void stage1(){ - int i = user.getID(); + // for avoiding edge cases, sets commitmentsArray[id - 1] BigInteger[] commitments = super.getCommitments(); - System.arraycopy(commitments, 0, commitmentsArray[i - 1], 0, commitmentsArray[i - 1].length); + System.arraycopy(commitments, 0, commitmentsArray[id - 1], 0, commitmentsArray[id - 1].length); + // broadcasts commitments CommitmentMessage commitment; - for (int k = 1; k <= commitmentsArray[i - 1].length; k ++){ + for (int k = 0; k <= t ; k ++){ commitment = CommitmentMessage.newBuilder() .setK(k) - .setCommitment(ByteString.copyFrom(commitmentsArray[i - 1][k - 1].toByteArray())) + .setCommitment(ByteString.copyFrom(commitmentsArray[id - 1][k].toByteArray())) .build(); user.broadcast(Mail.Type.COMMITMENT,commitment); } + // computes and sends shares SecretMessage secret; for (int j = 1; j <= n ; j++ ){ - if(j != i){ - myshares[j - 1] = super.getShare(j); + if(j != id){ secret = SecretMessage.newBuilder() - .setSecret(myshares[j - 1].asMessage()) + .setSecret(getShare(j).asMessage()) .build(); user.send(j, Mail.Type.SECRET,secret); } + else{ + shares[id - 1] = super.getShare(id); + } } while (!isStage1Complete()){ try { - Thread.sleep(30); + Thread.sleep(300); } catch (InterruptedException e) { // do nothing } } } + /** + * @return true iff all shares and commitments were received + */ private boolean isStage1Complete(){ - int id = user.getID(); - for (int j = 1 ; j <= n ; j++){ - if(id != j && shares[j - 1] == null) + for (int i = 1 ; i <= n ; i++){ + if(shares[i - 1] == null) return false; } @@ -99,28 +126,36 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ return true; } + /** + * @param secret + * @param i + * @return g ^ Sij == verify(j,Ai,zpstar) (mod p) + */ private boolean isValidSecret(Polynomial.Point secret, int i){ int j = secret.x.intValue(); - return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i],zpstar)); + return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i - 1],zpstar)); } + /** + * stage2 according to the protocol + * Pj verifies all the shares he received (using isValidSecret) + * if check fails for an index i, Pj broadcasts a complaint against Pi. + * Pj broadcasts yj value at the end of this stage + */ private void stage2(){ - int j = user.getID(); - QUAL = new HashSet(); + ys[id - 1] = super.getY(); ComplaintMessage complaint; for (int i = 1; i <= n ; i++ ){ - if(isValidSecret(shares[i - 1],j)) { - QUAL.add(i); - }else{ + if(id != i && !isValidSecret(shares[i - 1],i)) { //message = new Message(Type.Complaint, j) complaint = ComplaintMessage.newBuilder() .setId(i) .build(); user.broadcast(Mail.Type.COMPLAINT,complaint); - complainStates[j - 1][i - 1] = ComplainState.Waiting; + complainStates[i - 1][id - 1] = ComplainState.Waiting; } } - //sending y after Complaints + //broadcast y after all complaints YMessage yMessage = YMessage.newBuilder() .setY(ByteString.copyFrom(super.getY().toByteArray())) .build(); @@ -128,87 +163,99 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ while (!isStage2Complete()){ try { - Thread.sleep(30); + Thread.sleep(300); } catch (InterruptedException e) { // do nothing } } } + /** + * @return true iff all yi received for i = 1,...,n . + */ private boolean isStage2Complete() { - int id = user.getID(); for (int j = 1; j <= n ; j++) { - if (id != j && ys[j - 1] == null) + if (j != id && ys[j - 1] == null) return false; } - for (int i = 0; i < complainStates.length;i++){ - for (int j =0 ; j < complainStates[i].length;j++){ - switch (complainStates[i][j]){ - case Waiting: - return false; - default: - break; - } - } - } return true; } + + /** + * stage3 according to the protocol + * 1. if more than t players complain against a player Pi he is disqualified. + * 2. Pi broadcasts the share Sij for each complaining player Pj. + * 3. if any of the revealed shares fails the verification test, player Pi is disqualified. + * 4. set QUAL to be the set of non-disqualified players. + */ private void stage3(){ - for (int i = 0; i < complainStates.length;i++){ - ComplainState state = ComplainState.Non; - for (int j = 0 ; j < complainStates[i].length;j++){ - switch (complainStates[i][j]){ - case Disqualified: - state = ComplainState.Disqualified; - break; - case NonDisqualified: - if(state == ComplainState.Non){ - state = ComplainState.NonDisqualified; - } - break; - default: - break; - } - } - switch (state){ - case Disqualified: - if(QUAL.contains(i + 1)){ - QUAL.remove(i + 1); - } - break; - case NonDisqualified: - if (!QUAL.contains(i + 1)){ - QUAL.add(i + 1); - } + + // broadcasts Sij for each complaint against Pid + for (int j = 1 ; j <= complainStates[id - 1].length;j++) { + switch (complainStates[id - 1][j - 1]) { + case Waiting: + user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() + .setSecret(getShare(j).asMessage()) + .build()); + complainStates[id - 1][j - 1] = ComplainState.NonDisqualified; break; default: break; } } + + // wait until there is no complaint waiting for answer + for (int i = 0; i < complainStates.length;i++){ + for (int j = 0 ; j < complainStates[i].length;j++){ + while (complainStates[i][j].equals(ComplainState.Waiting)){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + // add each non-disqualified player to QUAL + boolean nonDisqualified; + for (int i = 1; i <= complainStates.length;i++){ + nonDisqualified = true; + for (int j = 1 ; j <= complainStates[i - 1].length;j++){ + nonDisqualified &= complainStates[i - 1][j - 1].equals(ComplainState.Disqualified); + } + if(nonDisqualified){ + QUAL.add(i); + } + } } + /** + * 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 + */ private void stage4(){ - BigInteger y = zpstar.zero(); + this.y = zpstar.zero(); for (int i : QUAL) { - y = zpstar.add(y , ys[i - 1]); + this.y = zpstar.add(this.y , ys[i - 1]); } - this.commitments = new BigInteger[t]; BigInteger commitment; - for (int k = 1; k <= t ; k++){ + for (int k = 0; k <= t ; k++){ commitment = zpstar.zero(); for (int i : QUAL) { - commitment = zpstar.add(commitment,commitmentsArray[i - 1][k - 1]); + commitment = zpstar.add(commitment,commitmentsArray[i - 1][k]); } - commitments[k - 1] = commitment; + commitments[k] = commitment; } - int j = user.getID(); - BigInteger x = BigInteger.ZERO; + BigInteger xj = BigInteger.ZERO; for (int i : QUAL) { - x = x.add(shares[i - 1].y); + xj = xj.add(shares[i - 1].y); } - this.x = x.mod(q); + this.share = new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } @Override @@ -221,18 +268,8 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ return Arrays.clone(commitments); } - @Override - protected Polynomial.Point getShare(int i) { - return null; - } - @Override - public void run() { - stage1(); - stage2(); - stage3(); - stage4(); - } + private enum ComplainState{ Non, Waiting,Disqualified,NonDisqualified @@ -240,11 +277,7 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ private class Handler implements Network.MailHandler { - final int id; - - private Handler() { - this.id = user.getID(); - } + private Handler() {} void handelSecretMessage(Mail mail) throws InvalidProtocolBufferException { if(shares[mail.getSender() - 1] == null) { @@ -255,12 +288,12 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ }else{ int i = mail.getSender(); int j = secret.x.intValue(); - switch (complainStates[i][j]){ + switch (complainStates[i - 1][j - 1]){ case Waiting: if(isValidSecret(secret,i)){ - complainStates[i][j] = ComplainState.NonDisqualified; + complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; }else{ - complainStates[i][j] = ComplainState.Disqualified; + complainStates[i - 1][j - 1] = ComplainState.Disqualified; } break; default: @@ -291,22 +324,17 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ } void handelComplaintMessage(Mail mail) throws InvalidProtocolBufferException { + int id = user.getID(); if(!mail.getIsPrivate()) { //broadcast only ComplaintMessage complaintMessage = ComplaintMessage.parseFrom(mail.getMessage()); int i = complaintMessage.getId(); int j = mail.getSender(); - if(i == id){ - user.broadcast(Mail.Type.SECRET,SecretMessage.newBuilder() - .setSecret(myshares[j].asMessage()) - .build()); - }else{ - switch (complainStates[i - 1][j - 1]){ - case Non: - complainStates[i - 1][j - 1] = ComplainState.Waiting; - break; - default: - break; - } + switch (complainStates[i - 1][j - 1]){ + case Non: + complainStates[i - 1][j - 1] = ComplainState.Waiting; + break; + default: + break; } } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java index 3cc3c85..70ab678 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java @@ -7,6 +7,9 @@ import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; /** * Created by Tzlil on 2/7/2016. + * JointFeldamn protocol assumes all parties can communicate throw broadcast chanel + * and private chanel (for each pair) + * this class simulates it */ public class Network { @@ -28,7 +31,8 @@ public class Network { Integer id = availableIDs.poll(); if (id == null) return null; - return new User(id,messageHandler); + users[id - 1] = new User(id,messageHandler); + return users[id - 1]; } private boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ @@ -70,13 +74,12 @@ public class Network { private final MailHandler messageHandler; private final Queue mailbox; private final int ID; - + private final Thread receiverThread; public User(int ID, MailHandler messageHandler) { - this.mailbox = new ArrayBlockingQueue(n*n); + this.mailbox = new ArrayBlockingQueue(1 << n); this.ID = ID; this.messageHandler = messageHandler; - Thread thread = new Thread(new Receiver()); - thread.run(); + this.receiverThread = new Thread(new Receiver()); } public boolean send(int id, Mail.Type type,Message message){ @@ -88,7 +91,9 @@ public class Network { public int getID() { return ID; } - + public Thread getReceiverThread(){ + return receiverThread; + } private class Receiver implements Runnable{ @Override public void run() { diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index 71c93fa..53a50af 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -33,7 +33,6 @@ public class InterpolationTest { public Polynomial.Point[] randomPoints(Polynomial p){ Polynomial.Point[] points = new Polynomial.Point[p.getDegree() + 1]; BigInteger x; - Boolean b; Set set = new HashSet(); for (int i = 0; i < points.length; i++){ x = new BigInteger(bits,random); diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java new file mode 100644 index 0000000..98e58ed --- /dev/null +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -0,0 +1,57 @@ +package JointFeldmanProtocol; + +import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 2/9/2016. + */ +public class DKGTest { + + + DKG[] dkgs; + Thread[] threads; + 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 + ; + Network network = new Network(n); + dkgs = new DKG[n]; + threads = new Thread[n]; + for (int i = 0 ; i < n ; i++) { + dkgs[i] = new DKG(t, n, new BigInteger(q.bitLength(), random).mod(q), random, p, q, g, network); + threads[i] = new Thread(dkgs[i]); + } + } + + @Test + public void DKGTest() throws Exception { + for (int i = 0 ; i < threads.length ; i++){ + threads[i].start(); + } + for (int i = 0 ; i < threads.length ; i++){ + threads[i].join(); + } + + for (int i = 0; i < dkgs.length - 1 ; i++){ + assert (dkgs[i].getY().equals(dkgs[i+1].getY())); + } + } +} From 9a78330e29fb7d432c22e57683a0fce458c37ccf Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Tue, 16 Feb 2016 22:33:52 +0200 Subject: [PATCH 018/106] Working Integration test for Threaded BB Client supporting Batches. Haven't tested subscriptions yet. --- .../bulletinboard/MultiServerWorker.java | 20 +- .../SingleServerBulletinBoardClient.java | 318 ++++++++-- .../ThreadedBulletinBoardClient.java | 36 +- .../MultiServerBeginBatchWorker.java | 6 +- .../MultiServerCloseBatchWorker.java | 6 +- .../MultiServerGenericPostWorker.java | 16 +- .../MultiServerGenericReadWorker.java | 14 +- .../MultiServerGetRedundancyWorker.java | 12 +- .../MultiServerPostBatchDataWorker.java | 6 +- .../MultiServerPostBatchWorker.java | 6 +- .../MultiServerPostMessageWorker.java | 6 +- .../MultiServerReadBatchWorker.java | 6 +- .../MultiServerReadMessagesWorker.java | 6 +- .../SingleServerReadBatchWorker.java | 57 +- .../BulletinBoardClientIntegrationTest.java | 214 ------- ...dedBulletinBoardClientIntegrationTest.java | 541 ++++++++++++++++++ bulletin-board-server/build.gradle | 7 +- .../sqlserver/BulletinBoardSQLServer.java | 30 +- .../sqlserver/H2QueryProvider.java | 3 + .../sqlserver/MySQLQueryProvider.java | 3 + .../sqlserver/SQLiteQueryProvider.java | 3 + .../webapp/BulletinBoardWebApp.java | 6 +- .../AsyncBulletinBoardClient.java | 28 +- .../bulletinboard/BulletinBoardServer.java | 2 +- .../meerkat/bulletinboard/CompleteBatch.java | 50 ++ .../java/meerkat/util/BulletinBoardUtils.java | 65 +++ .../main/proto/meerkat/BulletinBoardAPI.proto | 12 +- 27 files changed, 1076 insertions(+), 403 deletions(-) delete mode 100644 bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java create mode 100644 bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java create mode 100644 meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java index 8db836f..727a922 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java @@ -2,7 +2,7 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import java.util.Collections; import java.util.Iterator; @@ -16,7 +16,7 @@ import java.util.concurrent.atomic.AtomicInteger; * This is a general class for handling multi-server work * It utilizes Single Server Clients to perform the actual per-server work */ -public abstract class MultiServerWorker extends BulletinClientWorker implements Runnable, ClientCallback{ +public abstract class MultiServerWorker extends BulletinClientWorker implements Runnable, FutureCallback{ private List clients; @@ -26,7 +26,7 @@ public abstract class MultiServerWorker extends BulletinClientWorker clientCallback; + private FutureCallback futureCallback; /** * Constructor @@ -35,11 +35,11 @@ public abstract class MultiServerWorker extends BulletinClientWorker clients, boolean shuffleClients, int minServers, IN payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { super(payload,maxRetry); @@ -50,7 +50,7 @@ public abstract class MultiServerWorker extends BulletinClientWorker extends BulletinClientWorker clients, int minServers, IN payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - this(clients, false, minServers, payload, maxRetry, clientCallback); + this(clients, false, minServers, payload, maxRetry, futureCallback); } @@ -74,7 +74,7 @@ public abstract class MultiServerWorker extends BulletinClientWorker extends BulletinClientWorker implements FutureCallback { private SingleServerWorker worker; - private ClientCallback clientCallback; + private FutureCallback futureCallback; - public RetryCallback(SingleServerWorker worker, ClientCallback clientCallback) { + public RetryCallback(SingleServerWorker worker, FutureCallback futureCallback) { this.worker = worker; - this.clientCallback = clientCallback; + this.futureCallback = futureCallback; } @Override public void onSuccess(T result) { - clientCallback.handleCallback(result); + futureCallback.onSuccess(result); } @Override @@ -107,19 +114,210 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i scheduleWorker(worker, this); } else { // No more retries: notify caller about failure - clientCallback.handleFailure(t); + futureCallback.onFailure(t); } } } + /** + * This callback ties together all the per-batch-data callbacks into a single callback + * It reports success back to the user only if all of the batch-data were successfully posted + * If any batch-data fails to post: this callback reports failure + */ + class PostBatchDataListCallback implements FutureCallback { - public SingleServerBulletinBoardClient(int threadPoolSize, long failDelayInMilliseconds) { + private FutureCallback callback; + private AtomicInteger batchDataRemaining; + private AtomicBoolean aggregatedResult; + + public PostBatchDataListCallback(int batchDataLength, FutureCallback callback) { + + this.callback = callback; + this.batchDataRemaining = new AtomicInteger(batchDataLength); + this.aggregatedResult = new AtomicBoolean(false); + + } + + @Override + public void onSuccess(Boolean result) { + + if (result){ + this.aggregatedResult.set(true); + } + + if (batchDataRemaining.decrementAndGet() == 0){ + callback.onSuccess(this.aggregatedResult.get()); + } + } + + @Override + public void onFailure(Throwable t) { + + // Notify caller about failure + callback.onFailure(t); + + } + } + + /** + * This callback ties together the different parts of a CompleteBatch as they arrive from the server + * It assembles a CompleteBatch from the parts and sends it to the user if all parts arrived + * If any part fails to arrive: it invokes the onFailure method + */ + class CompleteBatchReadCallback { + + private FutureCallback callback; + + private List batchDataList; + private BulletinBoardMessage batchMessage; + + private AtomicInteger remainingQueries; + private AtomicBoolean failed; + + public CompleteBatchReadCallback(FutureCallback callback) { + + this.callback = callback; + + remainingQueries = new AtomicInteger(2); + failed = new AtomicBoolean(false); + + } + + protected void combineAndReturn() { + + final String[] prefixes = { + BulletinBoardConstants.BATCH_ID_TAG_PREFIX, + BulletinBoardConstants.BATCH_TAG}; + + if (remainingQueries.decrementAndGet() == 0){ + + BeginBatchMessage beginBatchMessage = + BeginBatchMessage.newBuilder() + .setSignerId(batchMessage.getSig(0).getSignerId()) + .setBatchId(Integer.parseInt( + BulletinBoardUtils.findTagWithPrefix(batchMessage, BulletinBoardConstants.BATCH_ID_TAG_PREFIX))) + .addAllTag(BulletinBoardUtils.removePrefixTags(batchMessage, Arrays.asList(prefixes))) + .build(); + callback.onSuccess(new CompleteBatch(beginBatchMessage, batchDataList, batchMessage.getSig(0))); + } + + } + + protected void fail(Throwable t) { + if (failed.compareAndSet(false, true)) { + callback.onFailure(t); + } + } + + /** + * @return a FutureCallback for the Batch Data List that ties to this object + */ + public FutureCallback> asBatchDataListFutureCallback() { + return new FutureCallback>() { + + @Override + public void onSuccess(List result) { + batchDataList = result; + + combineAndReturn(); + } + + @Override + public void onFailure(Throwable t) { + fail(t); + } + + }; + } + + /** + * @return a FutureCallback for the Bulletin Board Message that ties to this object + */ + public FutureCallback> asBulletinBoardMessageListFutureCallback() { + return new FutureCallback>() { + + @Override + public void onSuccess(List result) { + if (result.size() < 1){ + onFailure(new IllegalArgumentException("Server returned empty message list")); + return; + } + + batchMessage = result.get(0); + + combineAndReturn(); + } + + @Override + public void onFailure(Throwable t) { + fail(t); + } + }; + } + + } + + + /** + * Inner class for handling returned values of subscription operations + * This class's methods also ensure continued operation of the subscription + */ + class SubscriptionCallback implements FutureCallback> { + + private SingleServerReadMessagesWorker worker; + private MessageHandler messageHandler; + + private MessageFilterList.Builder filterBuilder; + + public SubscriptionCallback(SingleServerReadMessagesWorker worker, MessageHandler messageHandler) { + this.worker = worker; + this.messageHandler = messageHandler; + filterBuilder = worker.getPayload().toBuilder(); + + } + + @Override + public void onSuccess(List result) { + + // Report new messages to user + messageHandler.handleNewMessages(result); + + // Remove last filter from list (MIN_ENTRY one) + filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); + + // Add updated MIN_ENTRY filter (entry number is successor of last received entry's number) + filterBuilder.addFilter(MessageFilter.newBuilder() + .setType(FilterType.MIN_ENTRY) + .setEntry(result.get(result.size() - 1).getEntryNum() + 1) + .build()); + + // Create new worker with updated task + worker = new SingleServerReadMessagesWorker(worker.serverAddress, filterBuilder.build(), 1); + + // Schedule the worker + scheduleWorker(worker, this); + + } + + @Override + public void onFailure(Throwable t) { + + // Notify client about failure + fail(); + + // Reschedule exact same task + scheduleWorker(worker, this); + } + } + + public SingleServerBulletinBoardClient(int threadPoolSize, long failDelayInMilliseconds, long subscriptionIntervalInMilliseconds) { executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)); this.failDelayInMilliseconds = failDelayInMilliseconds; + this.subscriptionIntervalInMilliseconds = subscriptionIntervalInMilliseconds; // Set server error time to a time sufficiently in the past to make new jobs go through lastServerErrorTime = System.currentTimeMillis() - failDelayInMilliseconds; @@ -147,7 +345,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback) { + public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback) { // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(meerkatDBs.get(0), msg, MAX_RETRIES); @@ -162,18 +360,18 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } - private class PostBatchDataCallback implements ClientCallback { + private class PostBatchDataCallback implements FutureCallback { private CompleteBatch completeBatch; - ClientCallback callback; + FutureCallback callback; - public PostBatchDataCallback(CompleteBatch completeBatch, ClientCallback callback) { + public PostBatchDataCallback(CompleteBatch completeBatch, FutureCallback callback) { this.completeBatch = completeBatch; this.callback = callback; } @Override - public void handleCallback(Boolean msg) { + public void onSuccess(Boolean msg) { closeBatch( CloseBatchMessage.newBuilder() .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) @@ -185,24 +383,24 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void handleFailure(Throwable t) { - callback.handleFailure(t); + public void onFailure(Throwable t) { + callback.onFailure(t); } } - private class BeginBatchCallback implements ClientCallback { + private class BeginBatchCallback implements FutureCallback { private CompleteBatch completeBatch; - ClientCallback callback; + FutureCallback callback; - public BeginBatchCallback(CompleteBatch completeBatch, ClientCallback callback) { + public BeginBatchCallback(CompleteBatch completeBatch, FutureCallback callback) { this.completeBatch = completeBatch; this.callback = callback; } @Override - public void handleCallback(Boolean msg) { + public void onSuccess(Boolean msg) { postBatchData( completeBatch.getBeginBatchMessage().getSignerId(), @@ -213,13 +411,13 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void handleFailure(Throwable t) { - callback.handleFailure(t); + public void onFailure(Throwable t) { + callback.onFailure(t); } } @Override - public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { + public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { beginBatch( completeBatch.getBeginBatchMessage(), @@ -233,7 +431,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback callback) { + public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerBeginBatchWorker worker = @@ -246,12 +444,16 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void postBatchData(ByteString signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback) { + int startPosition, FutureCallback callback) { BatchMessage.Builder builder = BatchMessage.newBuilder() .setSignerId(signerId) .setBatchId(batchId); + // Create a unified callback to aggregate successful posts + + PostBatchDataListCallback listCallback = new PostBatchDataListCallback(batchDataList.size(), callback); + // Iterate through data list for (BatchData data : batchDataList) { @@ -262,7 +464,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i new SingleServerPostBatchWorker(meerkatDBs.get(0), builder.build(), MAX_RETRIES); // Create worker with redundancy 1 and MAX_RETRIES retries - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback(worker, listCallback)); // Increment position in batch startPosition++; @@ -271,7 +473,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback) { + public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback) { postBatchData(signerId, batchId, batchDataList, 0, callback); @@ -279,21 +481,21 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void postBatchData(byte[] signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback) { + int startPosition, FutureCallback callback) { postBatchData(ByteString.copyFrom(signerId), batchId, batchDataList, startPosition, callback); } @Override - public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback) { postBatchData(signerId, batchId, batchDataList, 0, callback); } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerCloseBatchWorker worker = @@ -305,7 +507,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void getRedundancy(MessageID id, ClientCallback callback) { + public void getRedundancy(MessageID id, FutureCallback callback) { // Create worker with no retries SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(meerkatDBs.get(0), id, 1); @@ -316,7 +518,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void readMessages(MessageFilterList filterList, ClientCallback> callback) { + public void readMessages(MessageFilterList filterList, FutureCallback> callback) { // Create job with no retries SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); @@ -327,19 +529,65 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback) { + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { - // Create job with no retries - SingleServerReadBatchWorker worker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchSpecificationMessage, 1); + // Create job with no retries for retrieval of the Bulletin Board Message that defines the batch - // Submit job and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_TAG) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(batchSpecificationMessage.getSignerId()) + .build()) + .build(); + + SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); + + // Create job with no retries for retrieval of the Batch Data List + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchSpecificationMessage, 1); + + // Create callback that will combine the two worker products + CompleteBatchReadCallback completeBatchReadCallback = new CompleteBatchReadCallback(callback); + + // Submit jobs with wrapped callbacks + scheduleWorker(messageWorker, new RetryCallback(messageWorker, completeBatchReadCallback.asBulletinBoardMessageListFutureCallback())); + scheduleWorker(batchWorker, new RetryCallback(batchWorker, completeBatchReadCallback.asBatchDataListFutureCallback())); } @Override public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) { + // Remove all existing MIN_ENTRY filters and create new one that starts at 0 + + MessageFilterList.Builder filterListBuilder = filterList.toBuilder(); + + Iterator iterator = filterListBuilder.getFilterList().iterator(); + while (iterator.hasNext()) { + MessageFilter filter = iterator.next(); + + if (filter.getType() == FilterType.MIN_ENTRY){ + iterator.remove(); + } + } + filterListBuilder.addFilter(MessageFilter.newBuilder() + .setType(FilterType.MIN_ENTRY) + .setEntry(0) + .build()); + + // Create job with no retries + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterListBuilder.build(), 1); + + // Submit job and create callback + scheduleWorker(worker, new SubscriptionCallback(worker, messageHandler)); + } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 78d5dba..76e6236 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -1,5 +1,6 @@ package meerkat.bulletinboard; +import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.bulletinboard.workers.multiserver.*; @@ -37,6 +38,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple 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; @@ -59,11 +61,16 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple clients = new ArrayList(clientParams.getBulletinBoardAddressCount()); for (String address : clientParams.getBulletinBoardAddressList()){ - SingleServerBulletinBoardClient client = new SingleServerBulletinBoardClient(SERVER_THREADPOOL_SIZE, FAIL_DELAY); + + SingleServerBulletinBoardClient client = + new SingleServerBulletinBoardClient(SERVER_THREADPOOL_SIZE, FAIL_DELAY, SUBSCRIPTION_INTERVAL); + client.init(BulletinBoardClientParams.newBuilder() .addBulletinBoardAddress(address) .build()); + clients.add(client); + } } @@ -76,7 +83,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple * @throws CommunicationException */ @Override - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback){ + public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback){ // Create job MultiServerPostMessageWorker worker = @@ -93,7 +100,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback) { + public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { // Create job MultiServerPostBatchWorker worker = @@ -110,7 +117,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback callback) { + public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { // Create job MultiServerBeginBatchWorker worker = @@ -123,7 +130,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple @Override public void postBatchData(byte[] signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback) { + int startPosition, FutureCallback callback) { BatchDataContainer batchDataContainer = new BatchDataContainer(signerId, batchId, batchDataList, startPosition); @@ -137,7 +144,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback) { + public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback) { postBatchData(signerId, batchId, batchDataList, 0, callback); @@ -145,21 +152,21 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple @Override public void postBatchData(ByteString signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback) { + int startPosition, FutureCallback callback) { postBatchData(signerId.toByteArray(), batchId, batchDataList, startPosition, callback); } @Override - public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback) { + public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback) { postBatchData(signerId, batchId, batchDataList, 0, callback); } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback) { + public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { // Create job MultiServerCloseBatchWorker worker = @@ -177,7 +184,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple * Ignore communication exceptions in specific databases */ @Override - public void getRedundancy(MessageID id, ClientCallback callback) { + public void getRedundancy(MessageID id, FutureCallback callback) { // Create job MultiServerGetRedundancyWorker worker = @@ -194,7 +201,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple * If no operation is successful: return null (NOT blank list) */ @Override - public void readMessages(MessageFilterList filterList, ClientCallback> callback) { + public void readMessages(MessageFilterList filterList, FutureCallback> callback) { // Create job MultiServerReadMessagesWorker worker = @@ -206,7 +213,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback) { + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { // Create job MultiServerReadBatchWorker worker = @@ -227,6 +234,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple super.close(); try { + + for (SingleServerBulletinBoardClient client : clients){ + client.close(); + } + executorService.shutdown(); while (! executorService.isShutdown()) { executorService.awaitTermination(10, TimeUnit.SECONDS); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java index dc496d7..e0e92bb 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; @@ -13,9 +13,9 @@ public class MultiServerBeginBatchWorker extends MultiServerGenericPostWorker clients, int minServers, BeginBatchMessage payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java index 56b09c5..300440f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.CloseBatchMessage; @@ -13,9 +13,9 @@ public class MultiServerCloseBatchWorker extends MultiServerGenericPostWorker clients, int minServers, CloseBatchMessage payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java index 8b62d4e..4ff96b1 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.comm.CommunicationException; @@ -17,9 +18,9 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< public MultiServerGenericPostWorker(List clients, int minServers, T payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } @@ -35,11 +36,6 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< */ public void run() { - WebTarget webTarget; - Response response; - - int count = 0; // Used to count number of servers which contain the required message in a GET_REDUNDANCY request. - // Iterate through servers Iterator clientIterator = getClientIterator(); @@ -56,7 +52,7 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< } @Override - public void handleCallback(Boolean result) { + public void onSuccess(Boolean result) { if (result){ if (minServers.decrementAndGet() <= 0){ succeed(Boolean.TRUE); @@ -65,7 +61,7 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< } @Override - public void handleFailure(Throwable t) { + public void onFailure(Throwable t) { if (maxFailedServers.decrementAndGet() < 0){ fail(t); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java index 6f6b425..68fc020 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.comm.CommunicationException; @@ -18,9 +18,9 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW public MultiServerGenericReadWorker(List clients, int minServers, IN payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, true, minServers, payload, maxRetry, clientCallback); // Shuffle clients on creation to balance load + super(clients, true, minServers, payload, maxRetry, futureCallback); // Shuffle clients on creation to balance load clientIterator = getClientIterator(); @@ -41,10 +41,10 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW if (clientIterator.hasNext()) { - // Send request to Server + // Get next server SingleServerBulletinBoardClient client = clientIterator.next(); - // Retrieve answer + // Retrieve answer from server doRead(payload, client); } else { @@ -54,12 +54,12 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW } @Override - public void handleCallback(OUT msg) { + public void onSuccess(OUT msg) { succeed(msg); } @Override - public void handleFailure(Throwable t) { + public void onFailure(Throwable t) { run(); // Retry with next server } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java index 5675cb8..517dbdf 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.comm.CommunicationException; @@ -20,9 +20,9 @@ public class MultiServerGetRedundancyWorker extends MultiServerWorker clients, int minServers, MessageID payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); // Shuffle clients on creation to balance load + super(clients, minServers, payload, maxRetry, futureCallback); // Shuffle clients on creation to balance load serversContainingMessage = new AtomicInteger(0); totalContactedServers = new AtomicInteger(0); @@ -54,7 +54,7 @@ public class MultiServerGetRedundancyWorker extends MultiServerWorker 0.5) { serversContainingMessage.incrementAndGet(); @@ -67,8 +67,8 @@ public class MultiServerGetRedundancyWorker extends MultiServerWorker clients, int minServers, BatchDataContainer payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java index 7c2f586..1b1f3df 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.CompleteBatch; import meerkat.bulletinboard.SingleServerBulletinBoardClient; @@ -13,9 +13,9 @@ public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker clients, int minServers, CompleteBatch payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java index 33f9a3c..6d3d702 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostMessageWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.*; @@ -13,9 +13,9 @@ public class MultiServerPostMessageWorker extends MultiServerGenericPostWorker clients, int minServers, BulletinBoardMessage payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java index 737c15c..3d40c8a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.CompleteBatch; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.BatchSpecificationMessage; @@ -15,9 +15,9 @@ public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker clients, int minServers, BatchSpecificationMessage payload, int maxRetry, - ClientCallback clientCallback) { + FutureCallback futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java index b276eab..980d869 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessagesWorker.java @@ -1,6 +1,6 @@ package meerkat.bulletinboard.workers.multiserver; -import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; +import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.*; @@ -14,9 +14,9 @@ public class MultiServerReadMessagesWorker extends MultiServerGenericReadWorker< public MultiServerReadMessagesWorker(List clients, int minServers, MessageFilterList payload, int maxRetry, - ClientCallback> clientCallback) { + FutureCallback> futureCallback) { - super(clients, minServers, payload, maxRetry, clientCallback); + super(clients, minServers, payload, maxRetry, futureCallback); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java index 61556fc..11fc777 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java @@ -23,7 +23,7 @@ import static meerkat.bulletinboard.BulletinBoardConstants.BATCH_ID_TAG_PREFIX; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class SingleServerReadBatchWorker extends SingleServerWorker { +public class SingleServerReadBatchWorker extends SingleServerWorker> { public SingleServerReadBatchWorker(String serverAddress, BatchSpecificationMessage payload, int maxRetry) { super(serverAddress, payload, maxRetry); @@ -35,59 +35,13 @@ public class SingleServerReadBatchWorker extends SingleServerWorker call() throws CommunicationException{ Client client = clientLocal.get(); WebTarget webTarget; Response response; - // Set filters for the batch message metadata retrieval - - MessageFilterList messageFilterList = MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BATCH_ID_TAG_PREFIX + String.valueOf(payload.getBatchId())) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(payload.getSignerId()) - .build()) - .build(); - - // Send request to Server - - webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH); - response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post( - Entity.entity(messageFilterList, Constants.MEDIATYPE_PROTOBUF)); - - // Retrieve answer - - try { - - // If a BulletinBoardMessageList is returned: the read was successful - BulletinBoardMessage metadata = response.readEntity(BulletinBoardMessageList.class).getMessage(0); - - completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() - .setSignerId(payload.getSignerId()) - .setBatchId(payload.getBatchId()) - .addAllTag(metadata.getMsg().getTagList()) - .build()); - - completeBatch.setSignature(metadata.getSig(0)); - - } catch (ProcessingException | IllegalStateException e) { - - // Read failed - throw new CommunicationException("Could not contact the server"); - - } - finally { - response.close(); - } - // Get the batch data webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(READ_BATCH_PATH); @@ -98,9 +52,8 @@ public class SingleServerReadBatchWorker extends SingleServerWorker>(){})); + // If a BatchDataList is returned: the read was successful + return response.readEntity(BatchDataList.class).getDataList(); } catch (ProcessingException | IllegalStateException e) { @@ -112,8 +65,6 @@ public class SingleServerReadBatchWorker extends SingleServerWorker thrown; - - protected void genericHandleFailure(Throwable t){ - System.err.println(t.getCause() + " " + t.getMessage()); - thrown.add(t); - jobSemaphore.release(); - } - - private class PostCallback implements ClientCallback{ - - @Override - public void handleCallback(Boolean msg) { - System.err.println("Post operation completed"); - jobSemaphore.release(); - } - - @Override - public void handleFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private class RedundancyCallback implements ClientCallback{ - - private float minRedundancy; - - public RedundancyCallback(float minRedundancy) { - this.minRedundancy = minRedundancy; - } - - @Override - public void handleCallback(Float redundancy) { - System.err.println("Redundancy found is: " + redundancy); - jobSemaphore.release(); - assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); - } - - @Override - public void handleFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private class ReadCallback implements ClientCallback>{ - - private List expectedMsgList; - - public ReadCallback(List expectedMsgList) { - this.expectedMsgList = expectedMsgList; - } - - @Override - public void handleCallback(List messages) { - - System.err.println(messages); - jobSemaphore.release(); - - BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); - - assertThat(messages.size(), is(expectedMsgList.size())); - - Iterator expectedMessageIterator = expectedMsgList.iterator(); - Iterator receivedMessageIterator = messages.iterator(); - - while (expectedMessageIterator.hasNext()) { - assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); - } - - } - - @Override - public void handleFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private AsyncBulletinBoardClient bulletinBoardClient; - - private PostCallback postCallback; - private RedundancyCallback redundancyCallback; - private ReadCallback readCallback; - - 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); - - @Before - public void init(){ - - bulletinBoardClient = new ThreadedBulletinBoardClient(); - - List testDB = new LinkedList(); - testDB.add(BASE_URL); - - bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() - .addBulletinBoardAddress("http://localhost:8081") - .setMinRedundancy((float) 1.0) - .build()); - - postCallback = new PostCallback(); - redundancyCallback = new RedundancyCallback((float) 1.0); - - thrown = new Vector<>(); - jobSemaphore = new Semaphore(0); - - } - - @Test - public void postTest() { - - 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}; - - BulletinBoardMessage msg; - - MessageFilterList filterList; - List msgList; - - MessageID messageID; - - Comparator msgComparator = new BulletinBoardMessageComparator(); - - msg = BulletinBoardMessage.newBuilder() - .setMsg(UnsignedBulletinBoardMessage.newBuilder() - .addTag("Signature") - .addTag("Trustee") - .setData(ByteString.copyFrom(b1)) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.DSA) - .setData(ByteString.copyFrom(b2)) - .setSignerId(ByteString.copyFrom(b3)) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.ECDSA) - .setData(ByteString.copyFrom(b3)) - .setSignerId(ByteString.copyFrom(b2)) - .build()) - .build(); - - messageID = bulletinBoardClient.postMessage(msg,postCallback); - - try { - jobSemaphore.acquire(); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - bulletinBoardClient.getRedundancy(messageID,redundancyCallback); - - filterList = MessageFilterList.newBuilder() - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Signature") - .build() - ) - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Trustee") - .build() - ) - .build(); - - msgList = new LinkedList(); - msgList.add(msg); - - readCallback = new ReadCallback(msgList); - - bulletinBoardClient.readMessages(filterList, readCallback); - try { - jobSemaphore.acquire(2); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - bulletinBoardClient.close(); - - if (thrown.size() > 0) { - assert false; - } - - } - -} diff --git a/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java new file mode 100644 index 0000000..c266086 --- /dev/null +++ b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java @@ -0,0 +1,541 @@ +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.bulletinboard.AsyncBulletinBoardClient; +import meerkat.bulletinboard.CompleteBatch; +import meerkat.bulletinboard.GenericBatchDigitalSignature; +import meerkat.bulletinboard.ThreadedBulletinBoardClient; +import meerkat.comm.CommunicationException; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; + +import meerkat.protobuf.Voting.*; +import meerkat.util.BulletinBoardMessageComparator; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.number.OrderingComparison.*; + +import java.io.IOException; +import java.io.InputStream; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.*; +import java.util.concurrent.Semaphore; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class ThreadedBulletinBoardClientIntegrationTest { + + // Signature resources + + private GenericBatchDigitalSignature signers[]; + private ByteString[] signerIDs; + + private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12"; + + private static String KEYFILE_PASSWORD1 = "secret"; + private static String KEYFILE_PASSWORD3 = "shh"; + + public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + public static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; + + // Server data + + 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 and callbacks + + private AsyncBulletinBoardClient bulletinBoardClient; + + private PostCallback postCallback; + private PostCallback failPostCallback = new PostCallback(true,false); + + private RedundancyCallback redundancyCallback; + private ReadCallback readCallback; + private ReadBatchCallback readBatchCallback; + + // Sync and misc + + private Semaphore jobSemaphore; + private Vector thrown; + private Random random; + + // Constructor + + public ThreadedBulletinBoardClientIntegrationTest(){ + + signers = new GenericBatchDigitalSignature[2]; + signerIDs = new ByteString[signers.length]; + signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); + + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD1.toCharArray(); + + KeyStore.Builder keyStoreBuilder = null; + try { + keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); + + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); + password = KEYFILE_PASSWORD3.toCharArray(); + + keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); + signers[1].loadSigningCertificate(keyStoreBuilder); + + signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + + for (int i = 0 ; i < signers.length ; i++) { + signerIDs[i] = signers[i].getSignerID(); + } + + } catch (IOException e) { + System.err.println("Failed reading from signature file " + e.getMessage()); + fail("Failed reading from signature file " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("Failed reading certificate " + e.getMessage()); + fail("Failed reading certificate " + e.getMessage()); + } catch (KeyStoreException e) { + System.err.println("Failed reading keystore " + e.getMessage()); + fail("Failed reading keystore " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.err.println("Couldn't find signing algorithm " + e.getMessage()); + fail("Couldn't find signing algorithm " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + System.err.println("Couldn't find signing key " + e.getMessage()); + fail("Couldn't find signing key " + e.getMessage()); + } + + } + + // Callback definitions + + protected void genericHandleFailure(Throwable t){ + System.err.println(t.getCause() + " " + t.getMessage()); + thrown.add(t); + jobSemaphore.release(); + } + + private class PostCallback implements FutureCallback{ + + private boolean isAssert; + private boolean assertValue; + + public PostCallback() { + this(false); + } + + public PostCallback(boolean isAssert) { + this(isAssert,true); + } + + public PostCallback(boolean isAssert, boolean assertValue) { + this.isAssert = isAssert; + this.assertValue = assertValue; + } + + @Override + public void onSuccess(Boolean msg) { + System.err.println("Post operation completed"); + jobSemaphore.release(); + //TODO: Change Assert mechanism to exception one + if (isAssert) { + if (assertValue) { + assertThat("Post operation failed", msg, is(Boolean.TRUE)); + } else { + assertThat("Post operation succeeded unexpectedly", msg, is(Boolean.FALSE)); + } + } + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class RedundancyCallback implements FutureCallback{ + + private float minRedundancy; + + public RedundancyCallback(float minRedundancy) { + this.minRedundancy = minRedundancy; + } + + @Override + public void onSuccess(Float redundancy) { + System.err.println("Redundancy found is: " + redundancy); + jobSemaphore.release(); + assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class ReadCallback implements FutureCallback>{ + + private List expectedMsgList; + + public ReadCallback(List expectedMsgList) { + this.expectedMsgList = expectedMsgList; + } + + @Override + public void onSuccess(List messages) { + + System.err.println(messages); + jobSemaphore.release(); + + BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); + + assertThat(messages.size(), is(expectedMsgList.size())); + + Iterator expectedMessageIterator = expectedMsgList.iterator(); + Iterator receivedMessageIterator = messages.iterator(); + + while (expectedMessageIterator.hasNext()) { + assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); + } + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class ReadBatchCallback implements FutureCallback { + + private CompleteBatch expectedBatch; + + public ReadBatchCallback(CompleteBatch expectedBatch) { + this.expectedBatch = expectedBatch; + } + + @Override + public void onSuccess(CompleteBatch batch) { + + System.err.println(batch); + jobSemaphore.release(); + + assertThat("Batch returned is incorrect", batch, is(equalTo(expectedBatch))); + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + // Randomness generators + + private byte randomByte(){ + return (byte) random.nextInt(); + } + + private byte[] randomByteArray(int length) { + + byte[] randomBytes = new byte[length]; + + for (int i = 0; i < length ; i++){ + randomBytes[i] = randomByte(); + } + + return randomBytes; + + } + + private CompleteBatch createRandomBatch(int signer, int batchId, int length) throws SignatureException { + + CompleteBatch completeBatch = new CompleteBatch(); + + // Create data + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .setSignerId(signerIDs[signer]) + .setBatchId(batchId) + .addTag("Test") + .build()); + + for (int i = 0 ; i < length ; i++){ + + BatchData batchData = BatchData.newBuilder() + .setData(ByteString.copyFrom(randomByteArray(i))) + .build(); + + completeBatch.appendBatchData(batchData); + + } + + signers[signer].updateContent(completeBatch); + + completeBatch.setSignature(signers[signer].sign()); + + return completeBatch; + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + @Before + public void init(){ + + bulletinBoardClient = new ThreadedBulletinBoardClient(); + + random = new Random(0); // We use insecure randomness in tests for repeatability + + List testDB = new LinkedList(); + testDB.add(BASE_URL); + + bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() + .addBulletinBoardAddress("http://localhost:8081") + .setMinRedundancy((float) 1.0) + .build()); + + postCallback = new PostCallback(); + redundancyCallback = new RedundancyCallback((float) 1.0); + + thrown = new Vector<>(); + jobSemaphore = new Semaphore(0); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + @After + public void close() { + + bulletinBoardClient.close(); + + if (thrown.size() > 0) { + assert false; + } + + } + + /** + * Tests the standard post, redundancy and read methods + */ + @Test + public void postTest() { + + 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}; + + BulletinBoardMessage msg; + + MessageFilterList filterList; + List msgList; + + MessageID messageID; + + Comparator msgComparator = new BulletinBoardMessageComparator(); + + msg = BulletinBoardMessage.newBuilder() + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .addTag("Signature") + .addTag("Trustee") + .setData(ByteString.copyFrom(b1)) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.DSA) + .setData(ByteString.copyFrom(b2)) + .setSignerId(ByteString.copyFrom(b3)) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.ECDSA) + .setData(ByteString.copyFrom(b3)) + .setSignerId(ByteString.copyFrom(b2)) + .build()) + .build(); + + messageID = bulletinBoardClient.postMessage(msg,postCallback); + + try { + jobSemaphore.acquire(); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + bulletinBoardClient.getRedundancy(messageID,redundancyCallback); + + filterList = MessageFilterList.newBuilder() + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Signature") + .build() + ) + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Trustee") + .build() + ) + .build(); + + msgList = new LinkedList(); + msgList.add(msg); + + readCallback = new ReadCallback(msgList); + + bulletinBoardClient.readMessages(filterList, readCallback); + try { + jobSemaphore.acquire(2); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + } + + /** + * Tests posting a batch by parts + * Also tests not being able to post to a closed batch + * @throws CommunicationException, SignatureException, InterruptedException + */ + @Test + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + final int SIGNER = 1; + final int BATCH_ID = 100; + final int BATCH_LENGTH = 100; + + CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); + + // Begin batch + + bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), postCallback); + + jobSemaphore.acquire(); + + // Post data + + bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), postCallback); + + jobSemaphore.acquire(); + + // Close batch + + CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() + .setBatchId(BATCH_ID) + .setBatchLength(BATCH_LENGTH) + .setSig(completeBatch.getSignature()) + .build(); + + bulletinBoardClient.closeBatch(closeBatchMessage, postCallback); + + jobSemaphore.acquire(); + + // Attempt to open batch again + + bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), failPostCallback); + + // Attempt to add batch data + + bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), failPostCallback); + + jobSemaphore.acquire(2); + + // Read batch data + + BatchSpecificationMessage batchSpecificationMessage = + BatchSpecificationMessage.newBuilder() + .setSignerId(signerIDs[SIGNER]) + .setBatchId(BATCH_ID) + .setStartPosition(0) + .build(); + + readBatchCallback = new ReadBatchCallback(completeBatch); + + bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + + jobSemaphore.acquire(); + + } + + /** + * Posts a complete batch message + * Checks reading od the message + * @throws CommunicationException, SignatureException, InterruptedException + */ + @Test + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + final int SIGNER = 0; + final int BATCH_ID = 101; + final int BATCH_LENGTH = 50; + + // Post batch + + CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); + + bulletinBoardClient.postBatch(completeBatch,postCallback); + + jobSemaphore.acquire(); + + // Read batch + + BatchSpecificationMessage batchSpecificationMessage = + BatchSpecificationMessage.newBuilder() + .setSignerId(signerIDs[SIGNER]) + .setBatchId(BATCH_ID) + .setStartPosition(0) + .build(); + + readBatchCallback = new ReadBatchCallback(completeBatch); + + bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + + jobSemaphore.acquire(); + + } + + /** + * Tests that an unopened batch cannot be closed + * @throws CommunicationException, InterruptedException + */ + @Test + public void testInvalidBatchClose() throws CommunicationException, InterruptedException { + + final int NON_EXISTENT_BATCH_ID = 999; + + CloseBatchMessage closeBatchMessage = + CloseBatchMessage.newBuilder() + .setBatchId(NON_EXISTENT_BATCH_ID) + .setBatchLength(1) + .setSig(Crypto.Signature.getDefaultInstance()) + .build(); + + // Try to close the (unopened) batch; + + bulletinBoardClient.closeBatch(closeBatchMessage, failPostCallback); + + jobSemaphore.acquire(); + + } + +} diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 21604d1..59045a2 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -48,7 +48,7 @@ dependencies { // JDBC connections compile 'org.springframework:spring-jdbc:4.2.+' - compile 'org.xerial:sqlite-jdbc:3.7.+' + compile 'org.xerial:sqlite-jdbc:3.8.+' compile 'mysql:mysql-connector-java:5.1.+' compile 'com.h2database:h2:1.0.+' @@ -89,6 +89,11 @@ task h2Test(type: Test) { outputs.upToDateWhen { false } } +task liteTest(type: Test) { + include '**/*SQLite*Test*' + outputs.upToDateWhen { false } +} + task dbTest(type: Test) { include '**/*H2*Test*' include '**/*MySQL*Test*' diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 5b4fac9..a6313b6 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -177,8 +177,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ case MSG_ID: return MSG_ID; - case EXACT_ENTRY: // Go through - case MAX_ENTRY: + case EXACT_ENTRY: // Go through + case MAX_ENTRY: // Go through + case MIN_ENTRY: return ENTRY_NUM; case SIGNER_ID: @@ -253,12 +254,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ switch (messageFilter.getType()) { - case MSG_ID: // Go through + case MSG_ID: // Go through case SIGNER_ID: return messageFilter.getId().toByteArray(); - case EXACT_ENTRY: // Go through - case MAX_ENTRY: + case EXACT_ENTRY: // Go through + case MAX_ENTRY: // Go through + case MIN_ENTRY: return messageFilter.getEntry(); case TAG: @@ -653,7 +655,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ for (int i=0 ; i < tags.length ; i++) { namedParameters[i] = new MapSqlParameterSource(); - namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(0),message.getSignerId()); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(0),message.getSignerId().toByteArray()); namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(1),message.getBatchId()); namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(2),tags[i]); } @@ -675,7 +677,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ String sql = sqlQueryProvider.getSQLString(QueryType.INSERT_BATCH_DATA); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId().toByteArray()); namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId()); namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum()); namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData().toByteArray()); @@ -700,7 +702,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),signerId); + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),signerId.toByteArray()); namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),batchId); List lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); @@ -733,7 +735,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),signerId); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),signerId.toByteArray()); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),batchId); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning @@ -775,7 +777,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_TAGS); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(0), signerId); + namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(0), signerId.toByteArray()); namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(1), batchId); jdbcTemplate.update(sql, namedParameters); @@ -786,7 +788,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } @Override - public List readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException{ + public BatchDataList readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException{ // Check that batch is closed if (!isBatchClosed(message.getSignerId(), message.getBatchId())) { @@ -796,11 +798,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId().toByteArray()); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),message.getStartPosition()); - return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); + return BatchDataList.newBuilder() + .addAllData(jdbcTemplate.query(sql, namedParameters, new BatchDataMapper())) + .build(); } @Override diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index 14bf9e2..659d9c3 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -134,6 +134,8 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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: @@ -157,6 +159,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider switch(filterType) { case EXACT_ENTRY: // Go through case MAX_ENTRY: // Go through + case MIN_ENTRY: // Go through case MAX_MESSAGES: return "INT"; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index c8357a3..e3bdef0 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -151,6 +151,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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: @@ -174,6 +176,7 @@ public class MySQLQueryProvider implements SQLQueryProvider { switch(filterType) { case EXACT_ENTRY: // Go through case MAX_ENTRY: // Go through + case MIN_ENTRY: // Go through case MAX_MESSAGES: return "INT"; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index d796789..b581b87 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -54,6 +54,8 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi 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: @@ -77,6 +79,7 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi switch(filterType) { case EXACT_ENTRY: // Go through case MAX_ENTRY: // Go through + case MIN_ENTRY: // Go through case MAX_MESSAGES: return "INTEGER"; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index fe3d2fc..766af19 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -106,6 +106,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Override public BoolMsg beginBatch(BeginBatchMessage message) { try { + init(); return bulletinBoard.beginBatch(message); } catch (CommunicationException e) { System.err.println(e.getMessage()); @@ -120,6 +121,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Override public BoolMsg postBatchMessage(BatchMessage batchMessage) { try { + init(); return bulletinBoard.postBatchMessage(batchMessage); } catch (CommunicationException e) { System.err.println(e.getMessage()); @@ -134,6 +136,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Override public BoolMsg closeBatchMessage(CloseBatchMessage message) { try { + init(); return bulletinBoard.closeBatchMessage(message); } catch (CommunicationException e) { System.err.println(e.getMessage()); @@ -146,8 +149,9 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public List readBatch(BatchSpecificationMessage message) { + public BatchDataList readBatch(BatchSpecificationMessage message) { try { + init(); return bulletinBoard.readBatch(message); } catch (CommunicationException | IllegalArgumentException e) { System.err.println(e.getMessage()); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 7732fcb..c6e330c 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -1,5 +1,6 @@ package meerkat.bulletinboard; +import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.BulletinBoardAPI.*; @@ -10,11 +11,6 @@ import java.util.List; */ public interface AsyncBulletinBoardClient extends BulletinBoardClient { - public interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - public interface MessageHandler { void handleNewMessages(List messageList); } @@ -25,7 +21,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a class containing methods to handle the result of the operation * @return a unique message ID for the message, that can be later used to retrieve the batch */ - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback); /** * Perform an end-to-end post of a signed batch message @@ -33,14 +29,14 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a class containing methods to handle the result of the operation * @return a unique identifier for the batch message */ - public MessageID postBatch(CompleteBatch completeBatch, ClientCallback callback); + public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback); /** * This message informs the server about the existence of a new batch message and supplies it with the tags associated with it * @param beginBatchMessage contains the data required to begin the batch * @param callback is a callback function class for handling results of the operation */ - public void beginBatch(BeginBatchMessage beginBatchMessage, ClientCallback callback); + public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback); /** * This method posts batch data into an (assumed to be open) batch @@ -54,30 +50,30 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a callback function class for handling results of the operation */ public void postBatchData(byte[] signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback); + int startPosition, FutureCallback callback); /** * Overloading of the postBatchData method which starts at the first position in the batch */ - public void postBatchData(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback); /** * Overloading of the postBatchData method which uses ByteString */ public void postBatchData(ByteString signerId, int batchId, List batchDataList, - int startPosition, ClientCallback callback); + int startPosition, FutureCallback callback); /** * Overloading of the postBatchData method which uses ByteString and starts at the first position in the batch */ - public void postBatchData(ByteString signerId, int batchId, List batchDataList, ClientCallback callback); + public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback); /** * Attempts to close a batch message * @param closeBatchMessage contains the data required to close the batch * @param callback is a callback function class for handling results of the operation */ - public void closeBatch(CloseBatchMessage closeBatchMessage, ClientCallback callback); + public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback); /** * Check how "safe" a given message is in an asynchronous manner @@ -85,7 +81,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param id is the unique message identifier for retrieval * @param callback is a callback function class for handling results of the operation */ - public void getRedundancy(MessageID id, ClientCallback callback); + public void getRedundancy(MessageID id, FutureCallback callback); /** * Read all messages posted matching the given filter in an asynchronous manner @@ -95,14 +91,14 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering). * @param callback is a callback function class for handling results of the operation */ - public void readMessages(MessageFilterList filterList, ClientCallback> callback); + public void readMessages(MessageFilterList filterList, FutureCallback> callback); /** * Read a given batch message from the bulletin board * @param batchSpecificationMessage contains the data required to specify a single batch instance * @param callback is a callback class for handling the result of the operation */ - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, ClientCallback callback); + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback); /** * Subscribes to a notifier that will return any new messages on the server that match the given filters diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index 70721a7..cbf06ff 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -75,7 +75,7 @@ public interface BulletinBoardServer{ * @throws CommunicationException on DB connection error * @throws IllegalArgumentException if message does not specify a batch */ - public List readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException; + public BatchDataList readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException; /** * This method closes the connection to the DB diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 19c57e3..227c7ca 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -2,6 +2,7 @@ package meerkat.bulletinboard; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.*; +import meerkat.util.BulletinBoardMessageComparator; import java.util.LinkedList; import java.util.List; @@ -48,6 +49,14 @@ public class CompleteBatch { return signature; } + public CloseBatchMessage getCloseBatchMessage() { + return CloseBatchMessage.newBuilder() + .setBatchId(getBeginBatchMessage().getBatchId()) + .setBatchLength(getBatchDataList().size()) + .setSig(getSignature()) + .build(); + } + public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) { this.beginBatchMessage = beginBatchMessage; } @@ -64,4 +73,45 @@ public class CompleteBatch { signature = newSignature; } + @Override + public boolean equals(Object other) { + + if (!(other instanceof CompleteBatch)) { + return false; + } + + CompleteBatch otherBatch = (CompleteBatch) other; + + boolean result = true; + + if (beginBatchMessage == null) { + if (otherBatch.getBeginBatchMessage() != null) + return false; + } else { + result = result && beginBatchMessage.equals(otherBatch.getBeginBatchMessage()); + } + + if (batchDataList == null) { + if (otherBatch.getBatchDataList() != null) + return false; + } else { + result = result && batchDataList.equals(otherBatch.getBatchDataList()); + } + + if (signature == null) { + if (otherBatch.getSignature() != null) + return false; + } else { + result = result && signature.equals(otherBatch.getSignature()); + } + + return result; + + } + + @Override + public String toString() { + return "Batch " + beginBatchMessage.getSignerId().toString() + ":" + beginBatchMessage.getBatchId(); + } + } diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java new file mode 100644 index 0000000..b19bab3 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java @@ -0,0 +1,65 @@ +package meerkat.util; + +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 16-Feb-16. + */ +public class BulletinBoardUtils { + + /** + * Searches the tags in the message for one that begins with given prefix + * @param message is the message to search + * @param prefix is the given prefix + * @return the tag without the prefix, if found, or null if not found + */ + public static String findTagWithPrefix(BulletinBoardMessage message, String prefix) { + + for (String tag : message.getMsg().getTagList()){ + if (tag.startsWith(prefix)) { + return tag.substring(prefix.length()); + } + } + + return null; + + } + + /** + * Searches the tags in a message for tags that do not contain a given list of prefixes + * @param message is the message to search + * @param prefixes is the list of prefixes + * @return a list of the tags that do *not* contain any of the given prefixes + */ + public static List removePrefixTags(BulletinBoardMessage message, Iterable prefixes) { + + if (prefixes == null) + return message.getMsg().getTagList(); + + List result = new LinkedList<>(); + + for (String tag : message.getMsg().getTagList()){ + + boolean found = false; + + for (String prefix : prefixes){ + if (tag.startsWith(prefix)){ + found = true; + break; + } + } + + if (!found) { + result.add(tag); + } + + } + + return result; + + } + +} diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 2ae4068..b86debd 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -50,13 +50,14 @@ 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) - SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer) - TAG = 4; // Find all entries in database that have a specific tag + 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 // 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 = 5; // Return at most some specified number of messages + MAX_MESSAGES = 6; // Return at most some specified number of messages } message MessageFilter { @@ -98,6 +99,11 @@ 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 From 210cc327ac8ed48ae9cd0fb8f9d8976f8269b9b3 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Wed, 17 Feb 2016 22:58:20 +0200 Subject: [PATCH 019/106] secure dkg without stage 4 --- .../main/java/Communication/MailHandler.java | 43 +++ .../java/Communication/MessageHandler.java | 14 + .../src/main/java/Communication/Network.java | 70 ++++ .../src/main/java/Communication/User.java | 68 ++++ .../VerifiableSecretSharing.java | 50 ++- ...VerifiableSecretSharingMessageHandler.java | 40 ++ .../main/java/JointFeldmanProtocol/DKG.java | 362 ------------------ .../DistributedKeyGeneration.java | 216 +++++++++++ ...istributedKeyGenerationMessageHandler.java | 161 ++++++++ .../java/JointFeldmanProtocol/Network.java | 124 ------ .../SecureDistributedKeyGeneration.java | 68 ++++ ...istributedKeyGenerationMessageHandler.java | 61 +++ .../LagrangePolynomial.java | 2 +- .../ShamirSecretSharing/Polynomial.java | 14 +- .../ShamirSecretSharing/SecretSharing.java | 50 ++- .../SecretSharingMessageHandler.java | 47 +++ .../VerifiableSecretSharingTest.java | 10 +- .../java/JointFeldmanProtocol/DKGTest.java | 107 ++++-- .../PolynomialTests/AddTest.java | 4 +- .../PolynomialTests/InterpolationTest.java | 4 +- .../PolynomialTests/MulByConstTest.java | 4 +- .../PolynomialTests/MulTest.java | 4 +- .../PolynomialTests/Utils.java | 4 +- .../SecretSharingTest.java | 12 +- .../src/main/proto/meerkat/DKGMessages.proto | 11 +- 25 files changed, 989 insertions(+), 561 deletions(-) create mode 100644 destributed-key-generation/src/main/java/Communication/MailHandler.java create mode 100644 destributed-key-generation/src/main/java/Communication/MessageHandler.java create mode 100644 destributed-key-generation/src/main/java/Communication/Network.java create mode 100644 destributed-key-generation/src/main/java/Communication/User.java create mode 100644 destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java delete mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java delete mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java rename destributed-key-generation/src/main/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/LagrangePolynomial.java (97%) rename destributed-key-generation/src/main/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/Polynomial.java (89%) rename destributed-key-generation/src/main/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/SecretSharing.java (64%) create mode 100644 destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/PolynomialTests/AddTest.java (87%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/PolynomialTests/InterpolationTest.java (92%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/PolynomialTests/MulByConstTest.java (87%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/PolynomialTests/MulTest.java (88%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/PolynomialTests/Utils.java (76%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => }/ShamirSecretSharing/SecretSharingTest.java (89%) diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/Communication/MailHandler.java new file mode 100644 index 0000000..c70032f --- /dev/null +++ b/destributed-key-generation/src/main/java/Communication/MailHandler.java @@ -0,0 +1,43 @@ +package Communication; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/14/2016. + */ +public class MailHandler { + + private MessageHandler messageHandler; + + public MailHandler(MessageHandler messageHandler){ + this.messageHandler = messageHandler; + } + + public MessageHandler getMessageHandler(){ + return messageHandler; + } + + public void handel(DKGMessages.Mail mail) throws InvalidProtocolBufferException { + switch (mail.getType()){ + case SECRET: + DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); + messageHandler.handelSecretMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,secretMessage); + break; + case COMMITMENT: + DKGMessages.CommitmentMessage commitmentMessage = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + messageHandler.handelCommitmentMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,commitmentMessage); + break; + case DONE: + DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); + messageHandler.handelDoneMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,doneMessage); + break; + case COMPLAINT: + DKGMessages.ComplaintMessage complaintMessage = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); + messageHandler.handelComplaintMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,complaintMessage); + break; + default: + break; + } + } +} diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/Communication/MessageHandler.java new file mode 100644 index 0000000..8d1447e --- /dev/null +++ b/destributed-key-generation/src/main/java/Communication/MessageHandler.java @@ -0,0 +1,14 @@ +package Communication; + +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/14/2016. + */ +public interface MessageHandler { + void handelComplaintMessage(int sender, boolean isBroadcast,DKGMessages.ComplaintMessage complaintMessage); + void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage); + void handelCommitmentMessage(int sender, boolean isBroadcast,DKGMessages.CommitmentMessage commitmentMessage); + void handelSecretMessage(int sender, boolean isBroadcast,DKGMessages.SecretMessage secretMessage); + void handelDoubleSecretMessage(int sender, boolean isBroadcast,DKGMessages.DoubleSecretMessage doubleSecretMessage); +} diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java new file mode 100644 index 0000000..fb6dca5 --- /dev/null +++ b/destributed-key-generation/src/main/java/Communication/Network.java @@ -0,0 +1,70 @@ +package Communication; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages.*; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; +/** + * Created by Tzlil on 2/7/2016. + * JointFeldamn protocol assumes all parties can communicate throw broadcast chanel + * and private chanel (for each pair) + * this class simulates it + */ +public class Network { + + protected final User[] users; + protected final int n; + protected final Queue availableIDs; + public static final int BROADCAST = 0; + + + public Network(int n) { + this.n = n; + this.users = new User[n]; + this.availableIDs = new ArrayBlockingQueue(n); + for (int id = 1; id <= n; id++){ + availableIDs.add(id); + } + } + + public User connect(MessageHandler messageHandler){ + Integer id = availableIDs.poll(); + if (id == null) + return null; + users[id - 1] = new User(id,this,new MailHandler(messageHandler)); + return users[id - 1]; + } + + protected boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ + if(destination < 1 || destination > n) + return false; + User user = users[destination - 1]; + if (user == null) + return false; + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(destination) + .setIsPrivate(true) + .setType(type) + .setMessage(message.toByteString()) + .build(); + return user.mailbox.add(mail); + } + + protected void sendBroadcast(User sender,Mail.Type type,Message message){ + User user; + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(BROADCAST) + .setIsPrivate(false) + .setType(type) + .setMessage(message.toByteString()) + .build(); + for (int i = 0 ; i < n ; i++){ + user = users[i]; + user.mailbox.add(mail); + } + } + +} diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java new file mode 100644 index 0000000..e28347c --- /dev/null +++ b/destributed-key-generation/src/main/java/Communication/User.java @@ -0,0 +1,68 @@ +package Communication; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +/** + * Created by Tzlil on 2/14/2016. + */ +public class User{ + protected final MailHandler mailHandler; + protected final Queue mailbox; + protected final int ID; + protected final Thread receiverThread; + private final Network network; + + protected User(int ID, Network network, MailHandler mailHandler) { + this.mailbox = new ArrayBlockingQueue(2 * network.n * network.n); + this.ID = ID; + this.mailHandler = mailHandler; + this.receiverThread = new Thread(new Receiver()); + this.network = network; + } + + public boolean send(int id, DKGMessages.Mail.Type type, Message message){ + return network.sendMessage(this,id,type,message); + } + + public void broadcast(DKGMessages.Mail.Type type, Message message){ + network.sendBroadcast(this,type,message); + } + + public MessageHandler getMessageHandler(){ + return mailHandler.getMessageHandler(); + } + + public int getID() { + return ID; + } + public Thread getReceiverThread(){ + return receiverThread; + } + private class Receiver implements Runnable{ + @Override + public void run() { + while (true){ + if (!mailbox.isEmpty()){ + try { + mailHandler.handel(mailbox.poll()); + } catch (InvalidProtocolBufferException e) { + e.printStackTrace(); + } + }else{ + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + } + + +} diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index eb3dc07..796aaa9 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -1,9 +1,12 @@ package FeldmanVerifiableSecretSharing; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.SecretSharing; -import org.bouncycastle.util.Arrays; -import org.factcenter.qilin.primitives.CyclicGroup; +import Communication.Network; +import Communication.User; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +import java.util.Arrays; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; @@ -21,8 +24,7 @@ public class VerifiableSecretSharing extends SecretSharing { protected final Zpstar zpstar; protected final BigInteger g; // public generator of group private final BigInteger y; // y = g ^ x - private final BigInteger[] commitments; - + protected final BigInteger[] commitments; /** * @param p a large prime * @param q a large prime dividing p - 1. @@ -30,8 +32,9 @@ public class VerifiableSecretSharing extends SecretSharing { * the generated group is a subgroup of Zp*. * it must be chosen such that computing discrete logarithms is hard in this group. */ - public VerifiableSecretSharing(int t, int n, BigInteger x, Random random,BigInteger p,BigInteger q,BigInteger g) { - super(t, n, x, random,q); + public VerifiableSecretSharing(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g + , User user) { + super(t, n, x, random,q,user); this.g = g; this.zpstar = new Zpstar(p); assert (zpstar.contains(g)); @@ -40,6 +43,11 @@ public class VerifiableSecretSharing extends SecretSharing { this.y = zpstar.multiply(g,x); } + public VerifiableSecretSharing(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g + , Network network) { + this(t,n,x,random,p,q,g,network.connect(new VerifiableSecretSharingMessageHandler(t))); + } + /** * @return commitments[i] = g ^ polynomial.coefficients[i] */ @@ -102,6 +110,30 @@ public class VerifiableSecretSharing extends SecretSharing { * @return copy of commitments */ public BigInteger[] getCommitments() { - return Arrays.clone(commitments); + return Arrays.copyOf(commitments,commitments.length); + } + + public DKGMessages.CommitmentMessage[] prepareCommitmentMessages(){ + DKGMessages.CommitmentMessage[] commitmentMessages = new DKGMessages.CommitmentMessage[t + 1]; + for (int k = 0; k <= t ; k ++) { + commitmentMessages[k] = DKGMessages.CommitmentMessage.newBuilder() + .setK(k) + .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) + .build(); + } + return commitmentMessages; + } + + protected void computeAndSendCommitments(){ + DKGMessages.CommitmentMessage[] commitmentMessages = prepareCommitmentMessages(); + for (int k = 0; k <= t ; k ++){ + user.broadcast(DKGMessages.Mail.Type.COMMITMENT,commitmentMessages[k]); + } + } + + @Override + public void run() { + super.run(); + computeAndSendCommitments(); } } diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java new file mode 100644 index 0000000..bfa23e5 --- /dev/null +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java @@ -0,0 +1,40 @@ +package FeldmanVerifiableSecretSharing; + +import Communication.Network; +import ShamirSecretSharing.SecretSharingMessageHandler; +import meerkat.protobuf.DKGMessages; + + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Created by Tzlil on 2/16/2016. + */ +public class VerifiableSecretSharingMessageHandler extends SecretSharingMessageHandler { + + private final BigInteger[] commitments; + + public VerifiableSecretSharingMessageHandler(int t) { + this.commitments = new BigInteger[t + 1]; + } + + public static BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ + return new BigInteger(commitmentMessage.getCommitment().toByteArray()); + } + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + if(isBroadcast) { // receive in broadcast only + commitments[commitmentMessage.getK()] = extractCommitment(commitmentMessage); + } + } + + public BigInteger[] getCommitments() { + return commitments; + } + + public BigInteger getY(){ + return commitments[0]; + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java deleted file mode 100644 index 2cbef48..0000000 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java +++ /dev/null @@ -1,362 +0,0 @@ -package JointFeldmanProtocol; - -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import org.bouncycastle.util.Arrays; -import meerkat.protobuf.DKGMessages.*; - -import java.math.BigInteger; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.Callable; - -/** - * Created by Tzlil on 2/5/2016. - * - * an implementation of a version of Pedersen's distributed key generation protocol - */ -public class DKG extends VerifiableSecretSharing implements Runnable{ - - private final int id; - private final Network.User user; // send and receive messages throw network - - private final BigInteger[] ys; // container for y values that - private final Polynomial.Point[] shares; // shares[i] equivalent to Si,id in terms of the protocol - private final BigInteger[][] commitmentsArray; // commitmentsArray[i] equivalent to Ai in terms of the protocol - private final ComplainState[][] complainStates; // complainStates[i][j] == state of Pj's complaint against Pi - - private final Set QUAL; // set of all non-disqualified parties - private final BigInteger[] commitments; // public verification values - private Polynomial.Point share; // final share of the secrete - private BigInteger y; // final public value - - - public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g,Network network) { - super(t, n, x, random, p, q, g); - - this.commitmentsArray = new BigInteger[n][t + 1]; - this.shares = new Polynomial.Point[n]; - this.user = network.connect(new Handler()); - this.id = user.getID(); - this.complainStates = new ComplainState[n][n]; - this.QUAL = new HashSet(); - this.ys = new BigInteger[n]; - this.commitments = new BigInteger[t + 1]; - - for (int i = 0; i < n; i ++){ - for (int j = 0 ; j < n ; j ++) - complainStates[i][j] = ComplainState.Non; - } - - } - - /** - * use for simulate real distributed protocol - */ - @Override - public void run() { - user.getReceiverThread().start(); - stage1(); - stage2(); - stage3(); - stage4(); - user.getReceiverThread().interrupt(); - } - - /** - * 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. - */ - private void stage1(){ - // for avoiding edge cases, sets commitmentsArray[id - 1] - BigInteger[] commitments = super.getCommitments(); - System.arraycopy(commitments, 0, commitmentsArray[id - 1], 0, commitmentsArray[id - 1].length); - - // broadcasts commitments - CommitmentMessage commitment; - for (int k = 0; k <= t ; k ++){ - commitment = CommitmentMessage.newBuilder() - .setK(k) - .setCommitment(ByteString.copyFrom(commitmentsArray[id - 1][k].toByteArray())) - .build(); - user.broadcast(Mail.Type.COMMITMENT,commitment); - } - - // computes and sends shares - SecretMessage secret; - for (int j = 1; j <= n ; j++ ){ - if(j != id){ - secret = SecretMessage.newBuilder() - .setSecret(getShare(j).asMessage()) - .build(); - user.send(j, Mail.Type.SECRET,secret); - } - else{ - shares[id - 1] = super.getShare(id); - } - } - while (!isStage1Complete()){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - - /** - * @return true iff all shares and commitments were received - */ - private boolean isStage1Complete(){ - for (int i = 1 ; i <= n ; i++){ - if(shares[i - 1] == null) - return false; - } - - for (int i = 0; i < commitmentsArray.length; i++){ - for (int j = 0; j < commitmentsArray[i].length; j++){ - if(commitmentsArray[i][j] == null) - return false; - } - } - return true; - } - - /** - * @param secret - * @param i - * @return g ^ Sij == verify(j,Ai,zpstar) (mod p) - */ - private boolean isValidSecret(Polynomial.Point secret, int i){ - int j = secret.x.intValue(); - return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i - 1],zpstar)); - } - - /** - * stage2 according to the protocol - * Pj verifies all the shares he received (using isValidSecret) - * if check fails for an index i, Pj broadcasts a complaint against Pi. - * Pj broadcasts yj value at the end of this stage - */ - private void stage2(){ - ys[id - 1] = super.getY(); - ComplaintMessage complaint; - for (int i = 1; i <= n ; i++ ){ - if(id != i && !isValidSecret(shares[i - 1],i)) { - //message = new Message(Type.Complaint, j) - complaint = ComplaintMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(Mail.Type.COMPLAINT,complaint); - complainStates[i - 1][id - 1] = ComplainState.Waiting; - } - } - //broadcast y after all complaints - YMessage yMessage = YMessage.newBuilder() - .setY(ByteString.copyFrom(super.getY().toByteArray())) - .build(); - user.broadcast(Mail.Type.Y,yMessage); - - while (!isStage2Complete()){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - - /** - * @return true iff all yi received for i = 1,...,n . - */ - private boolean isStage2Complete() { - for (int j = 1; j <= n ; j++) { - if (j != id && ys[j - 1] == null) - return false; - } - return true; - } - - - /** - * stage3 according to the protocol - * 1. if more than t players complain against a player Pi he is disqualified. - * 2. Pi broadcasts the share Sij for each complaining player Pj. - * 3. if any of the revealed shares fails the verification test, player Pi is disqualified. - * 4. set QUAL to be the set of non-disqualified players. - */ - private void stage3(){ - - // broadcasts Sij for each complaint against Pid - for (int j = 1 ; j <= complainStates[id - 1].length;j++) { - switch (complainStates[id - 1][j - 1]) { - case Waiting: - user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() - .setSecret(getShare(j).asMessage()) - .build()); - complainStates[id - 1][j - 1] = ComplainState.NonDisqualified; - break; - default: - break; - } - } - - // wait until there is no complaint waiting for answer - for (int i = 0; i < complainStates.length;i++){ - for (int j = 0 ; j < complainStates[i].length;j++){ - while (complainStates[i][j].equals(ComplainState.Waiting)){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - // add each non-disqualified player to QUAL - boolean nonDisqualified; - for (int i = 1; i <= complainStates.length;i++){ - nonDisqualified = true; - for (int j = 1 ; j <= complainStates[i - 1].length;j++){ - nonDisqualified &= complainStates[i - 1][j - 1].equals(ComplainState.Disqualified); - } - if(nonDisqualified){ - QUAL.add(i); - } - } - } - - /** - * 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 - */ - private void stage4(){ - this.y = zpstar.zero(); - for (int i : QUAL) { - this.y = zpstar.add(this.y , ys[i - 1]); - } - BigInteger commitment; - for (int k = 0; k <= t ; k++){ - commitment = zpstar.zero(); - for (int i : QUAL) { - commitment = zpstar.add(commitment,commitmentsArray[i - 1][k]); - } - commitments[k] = commitment; - } - - BigInteger xj = BigInteger.ZERO; - for (int i : QUAL) { - xj = xj.add(shares[i - 1].y); - } - this.share = new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); - } - - @Override - public BigInteger getY() { - return y; - } - - @Override - public BigInteger[] getCommitments() { - return Arrays.clone(commitments); - } - - - - - private enum ComplainState{ - Non, Waiting,Disqualified,NonDisqualified - } - - private class Handler implements Network.MailHandler { - - private Handler() {} - - void handelSecretMessage(Mail mail) throws InvalidProtocolBufferException { - if(shares[mail.getSender() - 1] == null) { - SecretMessage secretMessage = SecretMessage.parseFrom(mail.getMessage()); - Polynomial.Point secret = new Polynomial.Point(secretMessage.getSecret()); - if(mail.getIsPrivate()){ - shares[mail.getSender() - 1] = secret; - }else{ - int i = mail.getSender(); - int j = secret.x.intValue(); - switch (complainStates[i - 1][j - 1]){ - case Waiting: - if(isValidSecret(secret,i)){ - complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; - }else{ - complainStates[i - 1][j - 1] = ComplainState.Disqualified; - } - break; - default: - break; - } - } - } - } - - void handelCommitmentMessage(Mail mail) throws InvalidProtocolBufferException { - if(!mail.getIsPrivate()) { //broadcast only - CommitmentMessage commitmentMessage = CommitmentMessage.parseFrom(mail.getMessage()); - if (commitmentsArray[mail.getSender() - 1][commitmentMessage.getK()] == null) { - BigInteger commitment = new BigInteger(commitmentMessage.getCommitment().toByteArray()); - commitmentsArray[mail.getSender() - 1][commitmentMessage.getK()] = commitment; - } - } - } - - void handelYMessage(Mail mail) throws InvalidProtocolBufferException { - if(!mail.getIsPrivate()) { //broadcast only - if (ys[mail.getSender() - 1] == null) { - YMessage yMessage = YMessage.parseFrom(mail.getMessage()); - BigInteger y = new BigInteger(yMessage.getY().toByteArray()); - ys[mail.getSender() - 1] = y; - } - } - } - - void handelComplaintMessage(Mail mail) throws InvalidProtocolBufferException { - int id = user.getID(); - if(!mail.getIsPrivate()) { //broadcast only - ComplaintMessage complaintMessage = ComplaintMessage.parseFrom(mail.getMessage()); - int i = complaintMessage.getId(); - int j = mail.getSender(); - switch (complainStates[i - 1][j - 1]){ - case Non: - complainStates[i - 1][j - 1] = ComplainState.Waiting; - break; - default: - break; - } - } - } - - @Override - public void handel(Mail mail) throws InvalidProtocolBufferException { - switch (mail.getType()){ - case SECRET: - handelSecretMessage(mail); - break; - case COMMITMENT: - handelCommitmentMessage(mail); - break; - case Y: - handelYMessage(mail); - break; - case COMPLAINT: - handelComplaintMessage(mail); - break; - default: - break; - } - } - } -} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java new file mode 100644 index 0000000..a9bd311 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -0,0 +1,216 @@ +package JointFeldmanProtocol; + +import Communication.Network; +import Communication.User; +import ShamirSecretSharing.Polynomial; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import meerkat.protobuf.DKGMessages.*; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.Arrays; + +/** + * Created by Tzlil on 2/5/2016. + * + * an implementation of a version of Pedersen's distributed key generation protocol + */ +public class DistributedKeyGeneration extends VerifiableSecretSharing implements Runnable{ + + private final int id; + + private final Set QUAL; // set of all non-disqualified parties + private final BigInteger[] finalCommitments; // public verification values + + private Polynomial.Point share; // final share of the secrete + private BigInteger y; // final public value + + private final DistributedKeyGenerationMessageHandler handler; + + public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g + , User user) { + super(t, n, zi, random, p, q, g,user); + this.handler = (DistributedKeyGenerationMessageHandler) user.getMessageHandler(); + this.id = user.getID(); + this.QUAL = new HashSet(); + this.finalCommitments = new BigInteger[t + 1]; + Arrays.fill(this.finalCommitments,zpstar.zero()); + } + public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g + , Network network) { + this(t,n,zi,random,p,q,g,network.connect(new DistributedKeyGenerationMessageHandler(t,n,g,new Zpstar(p)))); + } + + /** + * use for simulate real distributed protocol + */ + @Override + public void run() { + user.getReceiverThread().start(); + stage1(); + stage2(); + stage3(); + stage4(); + user.getReceiverThread().interrupt(); + } + + /** + * 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(){ + super.run(); + while (!handler.isStage1Complete()){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + + /** + * stage2 according to the protocol + * Pj verifies all the shares he received (using isValidSecret) + * if check fails for an index i, Pj broadcasts a complaint against Pi. + * Pj broadcasts yj value at the end of this stage + */ + private void stage2(){ + ComplaintMessage complaint; + for (int i = 1; i <= n ; i++ ){ + if(id != i && !handler.isValidSecret(i)) { + //message = new Message(Type.Complaint, j) + complaint = ComplaintMessage.newBuilder() + .setId(i) + .build(); + user.broadcast(Mail.Type.COMPLAINT,complaint); + } + } + //broadcast done message after all complaints + DoneMessage doneMessage = DoneMessage.newBuilder().build(); + user.broadcast(Mail.Type.DONE,doneMessage); + + while (!handler.isStage2Complete()){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + + + + protected void answerComplaint(int j){ + user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() + .setSecret(getShare(j).asMessage()) + .build()); + } + /** + * stage3 according to the protocol + * 1. if more than t players complain against a player Pi he is disqualified. + * 2. Pi broadcasts the share Sij for each complaining player Pj. + * 3. if any of the revealed shares fails the verification test, player Pi is disqualified. + * 4. set QUAL to be the set of non-disqualified players. + */ + private void stage3(){ + DistributedKeyGenerationMessageHandler.ComplainState[][] complainStates = handler.getComplainStates(); + // broadcasts Sij for each complaint against Pid + for (int j = 1; j <= complainStates[id - 1].length; j++) { + switch (complainStates[id - 1][j - 1]) { + case Waiting: + answerComplaint(j); + break; + default: + break; + } + } + + // wait until there is no complaint waiting for answer + for (int i = 0; i < complainStates.length; i++){ + for (int j = 0; j < complainStates[i].length; j++){ + while (complainStates[i][j].equals(DistributedKeyGenerationMessageHandler.ComplainState.Waiting)){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + // add each non-disqualified player to QUAL + boolean nonDisqualified; + int counter; + for (int i = 1; i <= complainStates.length; i++){ + nonDisqualified = true; + counter = 0; + for (int j = 1; j <= complainStates[i - 1].length; j++){ + switch (complainStates[i - 1][j - 1]) { + case Non: + break; + case NonDisqualified: + counter++; + default: + nonDisqualified = false; + } + if(!nonDisqualified) + break; + } + if(nonDisqualified && counter <= t){ + QUAL.add(i); + } + } + } + + /** + * 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 + */ + private void stage4(){ + this.y = zpstar.zero(); + for (int i : QUAL) { + this.y = zpstar.add(this.y , handler.getY(i)); + } + + BigInteger[] commitments; + + for (int i : QUAL) { + commitments = handler.getCommitments(i); + for (int k = 0; k <= t; k++){ + this.finalCommitments[k] = zpstar.add(this.finalCommitments[k],commitments[k]); + } + } + + BigInteger xj = BigInteger.ZERO; + for (int i : QUAL) { + if( i == id){ + xj = xj.add(super.getShare(i).y); + }else{ + xj = xj.add(handler.getShare(i).y); + } + } + this.share = new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); + } + + @Override + public BigInteger getY() { + return y; + } + + @Override + public BigInteger[] getCommitments() { + return Arrays.copyOf(finalCommitments, finalCommitments.length); + } + + public Polynomial.Point getShare() { + return share; + } + +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java new file mode 100644 index 0000000..2314469 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java @@ -0,0 +1,161 @@ +package JointFeldmanProtocol; + +import Communication.MessageHandler; +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharingMessageHandler; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharingMessageHandler; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 2/16/2016. + */ +public class DistributedKeyGenerationMessageHandler implements MessageHandler { + + protected enum ComplainState{ + Non, Waiting,Disqualified,NonDisqualified + } + + protected final VerifiableSecretSharingMessageHandler[] vssHandlers; + protected final ComplainState[][] complainStates; // complainStates[i][j] == state of Pj's complaint against Pi + protected final BigInteger g; + protected final Zpstar zpstar; + protected final int n; + private final boolean[] doneFlags; + + public DistributedKeyGenerationMessageHandler(int t, int n, BigInteger g, Zpstar zpstar) { + this.g = g; + this.zpstar = zpstar; + this.n = n; + this.doneFlags = new boolean[n]; + this.vssHandlers = new VerifiableSecretSharingMessageHandler[n]; + for (int i = 1; i <= n ; i++){ + vssHandlers[i - 1] = new VerifiableSecretSharingMessageHandler(t); + } + this.complainStates = new ComplainState[n][n]; + for (int i = 0; i < n; i ++){ + for (int j = 0 ; j < n ; j ++) + this.complainStates[i][j] = ComplainState.Non; + } + } + + /** + * @return true iff all shares and commitments were received + */ + protected boolean isStage1Complete(){ + for (int i = 1 ; i <= n ; i++){ + if(vssHandlers[i - 1].getShare() == null) + return false; + } + + BigInteger[] commitments; + for (int i = 0; i < vssHandlers.length; i++){ + commitments = vssHandlers[i].getCommitments(); + for (int j = 0; j < commitments.length; j++){ + if(commitments[j] == null) + return false; + } + } + return true; + } + + /** + * @return true iff all flags in doneFlags are true + */ + protected boolean isStage2Complete() { + for (int j = 0; j < n ; j++) { + if(!doneFlags[j]) + return false; + } + return true; + } + + @Override + public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { + if(isBroadcast){ + int i = complaintMessage.getId(); + int j = sender; + switch (complainStates[i - 1][j - 1]){ + case Non: + complainStates[i - 1][j - 1] = ComplainState.Waiting; + break; + default: + break; + } + } + } + + @Override + public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { + if(isBroadcast) + this.doneFlags[sender - 1] = true; + } + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + vssHandlers[sender - 1].handelCommitmentMessage(sender, isBroadcast, commitmentMessage); + } + + + /** + * @param secret + * @param i + * @return g ^ Sij == verify(j,Ai,zpstar) (mod p) + */ + private boolean isValidSecret(Polynomial.Point secret, int i){ + int j = secret.x.intValue(); + BigInteger[] commitments = vssHandlers[i - 1].getCommitments(); + return zpstar.multiply(g,secret.y).equals(VerifiableSecretSharing.verify(j,commitments,zpstar)); + } + + protected boolean isValidSecret(int i){ + return isValidSecret(getShare(i),i); + } + + @Override + public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { + vssHandlers[sender - 1].handelSecretMessage(sender, isBroadcast, secretMessage); + if(isBroadcast){ + Polynomial.Point secret = SecretSharingMessageHandler.extractSecret(secretMessage); + int i = sender; + int j = secret.x.intValue(); + switch (complainStates[i - 1][j - 1]){ + case Waiting: + if(isValidSecret(secret,i)){ + complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; + }else{ + complainStates[i - 1][j - 1] = ComplainState.Disqualified; + } + break; + default: + break; + } + } + } + + @Override + public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + // ignore + } + + + protected ComplainState[][] getComplainStates() { + return complainStates; + } + + protected BigInteger getY(int i){ + return vssHandlers[i - 1].getY(); + } + + protected BigInteger[] getCommitments(int i){ + return vssHandlers[i -1].getCommitments(); + } + + protected Polynomial.Point getShare(int i){ + return vssHandlers[i-1].getShare(); + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java deleted file mode 100644 index 70ab678..0000000 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java +++ /dev/null @@ -1,124 +0,0 @@ -package JointFeldmanProtocol; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages.*; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; -/** - * Created by Tzlil on 2/7/2016. - * JointFeldamn protocol assumes all parties can communicate throw broadcast chanel - * and private chanel (for each pair) - * this class simulates it - */ -public class Network { - - private final User[] users; - private final int n; - private final Queue availableIDs; - - - public Network(int n) { - this.n = n; - this.users = new User[n]; - this.availableIDs = new ArrayBlockingQueue(n); - for (int id = 1; id <= n; id++){ - availableIDs.add(id); - } - } - - public User connect(MailHandler messageHandler){ - Integer id = availableIDs.poll(); - if (id == null) - return null; - users[id - 1] = new User(id,messageHandler); - return users[id - 1]; - } - - private boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ - if(destination < 1 || destination > n) - return false; - User user = users[destination - 1]; - if (user == null) - return false; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(destination) - .setIsPrivate(true) - .setType(type) - .setMessage(message.toByteString()) - .build(); - return user.mailbox.add(mail); - } - - private void sendBroadcast(User sender,Mail.Type type,Message message){ - User user; - int ID = sender.ID; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(0) - .setIsPrivate(false) - .setType(type) - .setMessage(message.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - if (i + 1 == ID) { - continue; - } - user = users[i]; - user.mailbox.add(mail); - } - } - - public class User{ - private final MailHandler messageHandler; - private final Queue mailbox; - private final int ID; - private final Thread receiverThread; - public User(int ID, MailHandler messageHandler) { - this.mailbox = new ArrayBlockingQueue(1 << n); - this.ID = ID; - this.messageHandler = messageHandler; - this.receiverThread = new Thread(new Receiver()); - } - - public boolean send(int id, Mail.Type type,Message message){ - return sendMessage(this,id,type,message); - } - public void broadcast(Mail.Type type,Message message){ - sendBroadcast(this,type,message); - } - public int getID() { - return ID; - } - public Thread getReceiverThread(){ - return receiverThread; - } - private class Receiver implements Runnable{ - @Override - public void run() { - while (true){ - if (!mailbox.isEmpty()){ - try { - messageHandler.handel(mailbox.poll()); - } catch (InvalidProtocolBufferException e) { - e.printStackTrace(); - } - }else{ - try { - Thread.sleep(30); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - } - - - } - - public interface MailHandler { - public void handel(Mail mail) throws InvalidProtocolBufferException; - } -} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java new file mode 100644 index 0000000..cf0a429 --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java @@ -0,0 +1,68 @@ +package SecureDistributedKeyGeneration; + +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import JointFeldmanProtocol.DistributedKeyGeneration; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 2/17/2016. + */ +public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { + + VerifiableSecretSharing verifiableSecretSharing; + + public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g + ,BigInteger h, Network network) { + super(t, n, zi, random, p, q, g, network.connect(new SecureDistributedKeyGenerationMessageHandler(t,n,g,new Zpstar(p)))); + this.verifiableSecretSharing = new VerifiableSecretSharing(t,n,new BigInteger(q.bitLength(), random).mod(q),random,p,q,h,user); + } + + @Override + protected void computeAndSendSecrets() { + DKGMessages.SecretMessage[] secretMessages1 = prepareSecretMessages(); + DKGMessages.SecretMessage[] secretMessages2 = verifiableSecretSharing.prepareSecretMessages(); + DKGMessages.DoubleSecretMessage doubleSecretMessage; + + for (int j = 1; j <= n ; j++ ){ + doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() + .setS1(secretMessages1[j - 1]) + .setS1(secretMessages2[j - 1]) + .build(); + user.send(j, DKGMessages.Mail.Type.SECRET,doubleSecretMessage); + } + } + + @Override + public DKGMessages.CommitmentMessage[] prepareCommitmentMessages() { + DKGMessages.CommitmentMessage[] commitmentMessages = new DKGMessages.CommitmentMessage[t + 1]; + BigInteger[] commitments2 = verifiableSecretSharing.getCommitments(); + for (int k = 0; k <= t ; k ++) { + commitmentMessages[k] = DKGMessages.CommitmentMessage.newBuilder() + .setK(k) + .setCommitment(ByteString.copyFrom(zpstar.add(commitments[k],commitments2[k]).toByteArray())) + .build(); + } + return commitmentMessages; + } + + @Override + protected void answerComplaint(int j) { + DKGMessages.SecretMessage secretMessage1 = DKGMessages.SecretMessage.newBuilder() + .setSecret(getShare(j).asMessage()) + .build(); + DKGMessages.SecretMessage secretMessage2 = DKGMessages.SecretMessage.newBuilder() + .setSecret(verifiableSecretSharing.getShare(j).asMessage()) + .build(); + + user.broadcast(DKGMessages.Mail.Type.SECRET, DKGMessages.DoubleSecretMessage.newBuilder() + .setS1(secretMessage1) + .setS2(secretMessage2) + .build()); + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java new file mode 100644 index 0000000..034f89c --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java @@ -0,0 +1,61 @@ +package SecureDistributedKeyGeneration; + +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import JointFeldmanProtocol.DistributedKeyGenerationMessageHandler; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharingMessageHandler; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 2/17/2016. + */ +public class SecureDistributedKeyGenerationMessageHandler extends DistributedKeyGenerationMessageHandler { + + private final SecretSharingMessageHandler[] ssHandlers; + public SecureDistributedKeyGenerationMessageHandler(int t, int n, BigInteger g, Zpstar zpstar) { + super(t, n, g, zpstar); + this.ssHandlers = new SecretSharingMessageHandler[n]; + } + + private boolean isValidSecret(Polynomial.Point secret1,Polynomial.Point secret2,int i){ + int j = secret1.x.intValue(); + BigInteger[] commitments = vssHandlers[i - 1].getCommitments(); + return zpstar.multiply(g,zpstar.add(secret1.y,secret2.y)).equals(VerifiableSecretSharing.verify(j,commitments,zpstar)); + } + + @Override + protected boolean isValidSecret(int i) { + return isValidSecret(getShare(i),ssHandlers[i - 1].getShare(),i); + } + + + @Override + public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + if(!isBroadcast){ + this.handelSecretMessage(sender,isBroadcast,doubleSecretMessage.getS1()); + ssHandlers[sender - 1].handelSecretMessage(sender,isBroadcast,doubleSecretMessage.getS2()); + }else{ + Polynomial.Point secret1 = SecretSharingMessageHandler.extractSecret(doubleSecretMessage.getS1()); + Polynomial.Point secret2 = SecretSharingMessageHandler.extractSecret(doubleSecretMessage.getS2()); + int i = sender; + int j = secret1.x.intValue(); + switch (complainStates[i - 1][j - 1]){ + case Waiting: + if(isValidSecret(secret1,secret2,i)){ + complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; + }else{ + complainStates[i - 1][j - 1] = ComplainState.Disqualified; + } + break; + default: + break; + } + } + } + + +} diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java similarity index 97% rename from destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java rename to destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java index 6754822..d3815ff 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java @@ -1,4 +1,4 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing; +package ShamirSecretSharing; import java.math.BigInteger; diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java similarity index 89% rename from destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java rename to destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index 2bdf2ad..1c8eb0e 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -1,4 +1,4 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing; +package ShamirSecretSharing; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; @@ -9,8 +9,8 @@ import java.math.BigInteger; * Created by Tzlil on 1/27/2016. */ public class Polynomial implements Comparable { - protected static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); // neutral for add - protected static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); // neutral for mul + public static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); // neutral for add + public static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); // neutral for mul private final int degree; private final BigInteger[] coefficients; @@ -45,7 +45,7 @@ public class Polynomial implements Comparable { @Override public String toString() { - return "FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests{" + + return "ShamirSecretSharing.PolynomialTests{" + "degree=" + degree + ", coefficients=" + java.util.Arrays.toString(coefficients) + '}'; @@ -101,7 +101,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z + * @return new ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z * new.image(x) = this.image(x) + other.image(x) */ public Polynomial add(Polynomial other){ @@ -123,7 +123,7 @@ public class Polynomial implements Comparable { /** * @param constant - * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree this.degree s.t for all x in Z + * @return new ShamirSecretSharing.PolynomialTests of degree this.degree s.t for all x in Z * new.image(x) = constant * this.image(x) */ public Polynomial mul(BigInteger constant){ @@ -138,7 +138,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests of degree this degree + other degree + 1 s.t for all x in Z + * @return new ShamirSecretSharing.PolynomialTests of degree this degree + other degree + 1 s.t for all x in Z * new.image(x) = this.image(x) * other.image(x) */ public Polynomial mul(Polynomial other){ diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java similarity index 64% rename from destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java rename to destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 9e3319d..de6b847 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -1,6 +1,10 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing; +package ShamirSecretSharing; +import Communication.Network; +import Communication.User; +import meerkat.protobuf.DKGMessages; + import java.math.BigInteger; import java.util.Random; @@ -8,11 +12,12 @@ import java.util.Random; * Created by Tzlil on 1/27/2016. * an implementation of Shamire's secret sharing scheme */ -public class SecretSharing { +public class SecretSharing implements Runnable{ protected final int t; protected final int n; protected final BigInteger q; + protected final User user; // send and receive messages throw network private final Polynomial polynomial; /** @@ -24,11 +29,16 @@ public class SecretSharing { * @param x secret, chosen from Zq * @param random use for generate random polynomial */ - public SecretSharing(int t, int n, BigInteger x, Random random,BigInteger q) { + public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q, Network network) { + this(t,n,x,random,q,network.connect(new SecretSharingMessageHandler())); + } + + public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q, User user) { this.q = q; this.t = t; this.n = n; this.polynomial = generateRandomPolynomial(x,random); + this.user = user; } /** @@ -53,18 +63,11 @@ public class SecretSharing { * * @return polynomial.image(i)%q */ - protected final Polynomial.Point getShare(int i){ + public Polynomial.Point getShare(int i){ assert (i > 0 && i <= n); return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); } - /** - * use for test only - */ - public Polynomial.Point getShareForTest(int i){ - return getShare(i); - } - /** * @param shares - subset of the original shares * @@ -99,8 +102,31 @@ public class SecretSharing { return q; } - protected Polynomial getPolynomial() { + public Polynomial getPolynomial() { return polynomial; } + + public DKGMessages.SecretMessage[] prepareSecretMessages(){ + DKGMessages.SecretMessage[] secretMessages = new DKGMessages.SecretMessage[n]; + for (int j = 1; j <= n ; j++ ){ + secretMessages[j - 1] = DKGMessages.SecretMessage.newBuilder() + .setSecret(getShare(j).asMessage()) + .build(); + } + return secretMessages; + } + + protected void computeAndSendSecrets(){ + DKGMessages.SecretMessage[] secretMessages = prepareSecretMessages(); + for (int j = 1; j <= n ; j++ ){ + user.send(j, DKGMessages.Mail.Type.SECRET,secretMessages[j - 1]); + } + } + + @Override + public void run() { + // computes and sends shares + computeAndSendSecrets(); + } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java new file mode 100644 index 0000000..6230c05 --- /dev/null +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java @@ -0,0 +1,47 @@ +package ShamirSecretSharing; + +import Communication.MessageHandler; +import Communication.Network; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/16/2016. + */ +public class SecretSharingMessageHandler implements MessageHandler{ + + private Polynomial.Point share; + + @Override + public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { + // ignore + } + + @Override + public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { + // ignore + } + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + // ignore + } + + @Override + public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + // ignore + } + + @Override + public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { + if(!isBroadcast) + this.share = extractSecret(secretMessage); + } + + public static Polynomial.Point extractSecret(DKGMessages.SecretMessage secretMessage){ + return new Polynomial.Point(secretMessage.getSecret()); + } + + public Polynomial.Point getShare() { + return share; + } +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index 8a4f15d..f773237 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -1,6 +1,7 @@ package FeldmanVerifiableSecretSharing; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import Communication.Network; +import ShamirSecretSharing.Polynomial; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; import org.junit.Test; @@ -31,11 +32,12 @@ public class VerifiableSecretSharingTest { }while (!g.equals(ZERO) && !zpstar.multiply(g,q).equals(ZERO));// sample from QRZp* int t = 8; int n = 20; - + Network network; verifiableSecretSharingArray = new VerifiableSecretSharing[tests]; for (int i = 0; i < verifiableSecretSharingArray.length; i++){ + network = new Network(n); verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n - ,new BigInteger(q.bitLength(),random).mod(q),random,p,q,g); + ,new BigInteger(q.bitLength(),random).mod(q),random,p,q,g,network); } } @@ -47,7 +49,7 @@ public class VerifiableSecretSharingTest { BigInteger[] commitments = verifiableSecretSharing.getCommitments(); BigInteger[] verifications = new BigInteger[n]; for (int i = 1 ; i <= shares.length; i ++){ - shares[i - 1] = verifiableSecretSharing.getShareForTest(i); + shares[i - 1] = verifiableSecretSharing.getShare(i); verifications[i - 1] = VerifiableSecretSharing.verify(i,commitments,zpstar); } BigInteger expected; diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index 98e58ed..9171f3d 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -1,10 +1,16 @@ package JointFeldmanProtocol; +import Communication.Network; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; 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.List; import java.util.Random; /** @@ -13,45 +19,98 @@ import java.util.Random; public class DKGTest { - DKG[] dkgs; - Thread[] threads; - int tests = 1 << 10; - Random random; - + DistributedKeyGeneration[][] dkgsArrays; + Thread[][] threadsArrays; + int tests = 10; + BigInteger p = BigInteger.valueOf(2903); + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + BigInteger[] secrets; @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(); + Random random = new Random(); BigInteger g; + int t = 9; + int n = 20; 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 - ; - Network network = new Network(n); - dkgs = new DKG[n]; - threads = new Thread[n]; - for (int i = 0 ; i < n ; i++) { - dkgs[i] = new DKG(t, n, new BigInteger(q.bitLength(), random).mod(q), random, p, q, g, network); - threads[i] = new Thread(dkgs[i]); + dkgsArrays = new DistributedKeyGeneration[tests][n]; + threadsArrays = new Thread[tests][n]; + secrets = new BigInteger[tests]; + for (int test = 0; test < tests; test++) { + do { + g = zpstar.sample(random); + } while (!g.equals(ZERO) && !zpstar.multiply(g, q).equals(ZERO));// sample from QRZp* + secrets[test] = BigInteger.ZERO; + Network network = new Network(n); + for (int i = 0; i < n; i++) { + BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); + secrets[test] = secrets[test].add(secret).mod(q); + dkgsArrays[test][i] = new DistributedKeyGeneration(t, n,secret, random, p, q, g, network); + threadsArrays[test][i] = new Thread(dkgsArrays[test][i]); + } } } - @Test - public void DKGTest() throws Exception { - for (int i = 0 ; i < threads.length ; i++){ + public void oneTest(Thread[] threads, DistributedKeyGeneration[] dkgs,BigInteger secret) throws Exception { + for (int i = 0; i < threads.length ; i++){ threads[i].start(); } - for (int i = 0 ; i < threads.length ; i++){ + for (int i = 0; i < threads.length ; i++){ threads[i].join(); } + int t = dkgs[0].getT(); + int n = dkgs[0].getN(); + Zpstar zpstar = dkgs[0].getZpstar(); + BigInteger g = dkgs[0].getGenerator(); + + // got the right public value + assert(zpstar.multiply(g,secret).equals(dkgs[0].getY())); + + // assert all players agreed on the same public value for (int i = 0; i < dkgs.length - 1 ; i++){ assert (dkgs[i].getY().equals(dkgs[i+1].getY())); } + + // assert valid verification values + BigInteger expected,verification; + for (int j = 1; j <= dkgs.length ; j++){ + expected = zpstar.multiply(g, dkgs[j - 1].getShare().y); + verification = VerifiableSecretSharing.verify(j, dkgs[j - 1].getCommitments(),zpstar); + assert (expected.equals(verification)); + } + + + // restore the secret from t + 1 random shares + Polynomial.Point[] shares = new Polynomial.Point[t + 1]; + for (int i = 0 ; i < shares.length; i++){ + shares[i] = dkgs[i].getShare(); + } + //List indexes = new ArrayList(n); + //for (int i = 1 ; i <= n; i ++){ + // indexes.add(i); + //} + //Random random = new Random(); + //int index; + //for (int i = 0 ; i < shares.length ; i++){ + // index = indexes.remove(random.nextInt(indexes.size())); + // shares[i] = dkgs[index - 1].getShare(); + //} + BigInteger calculatedSecret = SecretSharing.getSecrete(shares).mod(q); + + Polynomial polynomial = Polynomial.ZERO; + for (int i = 0 ; i < dkgs.length ; i++){ + polynomial = polynomial.add(dkgs[i].getPolynomial()); + } + + assert (calculatedSecret.equals(secret)); + + } + + @Test + public void secretSharingTest() throws Exception { + for (int i = 0 ; i < dkgsArrays.length; i ++){ + oneTest(threadsArrays[i],dkgsArrays[i],secrets[i]); + } } } diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java similarity index 87% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java index 1df4fef..288aed1 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java @@ -1,5 +1,5 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +package ShamirSecretSharing.PolynomialTests; +import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java similarity index 92% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index 53a50af..b1539cc 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -1,6 +1,6 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; +package ShamirSecretSharing.PolynomialTests; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java similarity index 87% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java index 6d9669a..0865058 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java @@ -1,6 +1,6 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; +package ShamirSecretSharing.PolynomialTests; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java similarity index 88% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java index fd4d761..418ea00 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java @@ -1,6 +1,6 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; +package ShamirSecretSharing.PolynomialTests; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java similarity index 76% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java index 67bd51c..47dca28 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/Utils.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java @@ -1,6 +1,6 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests; +package ShamirSecretSharing.PolynomialTests; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.Polynomial; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java similarity index 89% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java rename to destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java index bc96f7f..02b8898 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java @@ -1,6 +1,7 @@ -package FeldmanVerifiableSecretSharing.ShamirSecretSharing; +package ShamirSecretSharing; -import FeldmanVerifiableSecretSharing.ShamirSecretSharing.PolynomialTests.Utils; +import Communication.Network; +import Communication.User; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; import org.junit.Before; @@ -26,14 +27,17 @@ public class SecretSharingTest { public void settings(){ BigInteger p = BigInteger.valueOf(2903); group = new Zn(p); - int t = 10; + int t = 9; int n = 20; random = new Random(); secretSharingArray = new SecretSharing[tests]; secrets = new BigInteger[tests]; + Network network; + for (int i = 0; i < secretSharingArray.length; i++){ secrets[i] = group.sample(random); - secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,p); + network = new Network(n); + secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,p,network); } } diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto index e874f5a..c01b004 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -8,7 +8,7 @@ message Mail{ enum Type { SECRET = 0; COMMITMENT = 1; - Y = 2; + DONE = 2; COMPLAINT = 3; } int32 sender = 1; @@ -26,14 +26,17 @@ message SecretMessage { Point secret = 1; } +message DoubleSecretMessage{ + SecretMessage s1 = 1; + SecretMessage s2 = 2; +} + message CommitmentMessage{ int32 k = 1; bytes commitment = 2; } -message YMessage{ - bytes y = 1; -} +message DoneMessage{} message ComplaintMessage{ int32 id = 1; From aeb7c13436af18dde9455c82c40221ca0f6ba442 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 22 Feb 2016 08:04:01 +0200 Subject: [PATCH 020/106] Made read operations stream the results. Removed dependency on large Protobufs (BulletinBoardMessageList and BatchDataList). Partial implementation of Sync Query. Current version supports only H2 and MySQL (no SQLite support). --- .../bulletinboard/BulletinClientWorker.java | 2 +- .../bulletinboard/MultiServerWorker.java | 4 +- .../SimpleBulletinBoardClient.java | 2 +- .../SingleServerBulletinBoardClient.java | 56 ++-- .../bulletinboard/SingleServerWorker.java | 2 +- .../ThreadedBulletinBoardClient.java | 9 +- .../MultiServerGenericPostWorker.java | 2 - .../MultiServerGenericReadWorker.java | 4 +- .../MultiServerGetRedundancyWorker.java | 6 +- .../SingleServerGenericPostWorker.java | 4 +- .../SingleServerGetRedundancyWorker.java | 4 +- ...dedBulletinBoardClientIntegrationTest.java | 15 +- bulletin-board-server/build.gradle | 4 + .../sqlserver/BulletinBoardSQLServer.java | 265 ++++++++++++++---- .../sqlserver/H2QueryProvider.java | 18 +- .../sqlserver/MySQLQueryProvider.java | 27 +- .../mappers/BatchDataCallbackHandler.java | 32 +++ .../mappers/MessageCallbackHandler.java | 80 ++++++ .../sqlserver/mappers/MessageStubMapper.java | 31 ++ .../webapp/BulletinBoardWebApp.java | 94 ++++++- ...BulletinBoardSQLServerIntegrationTest.java | 38 ++- .../GenericBulletinBoardServerTest.java | 138 ++++++--- meerkat-common/build.gradle | 1 + .../bulletinboard/BulletinBoardConstants.java | 1 + .../bulletinboard/BulletinBoardServer.java | 19 +- .../meerkat/bulletinboard/CompleteBatch.java | 28 ++ .../java/meerkat/comm/MessageInputStream.java | 64 +++++ .../meerkat/comm/MessageOutputStream.java | 24 ++ .../src/main/java/meerkat/comm/Timestamp.java | 7 - .../util/BulletinBoardMessageGenerator.java | 98 +++++++ .../java/meerkat/util/BulletinBoardUtils.java | 42 +++ .../meerkat/util/TimeStampComparator.java | 30 ++ .../main/proto/meerkat/BulletinBoardAPI.proto | 51 +++- .../java/meerkat/comm/MessageStreamTest.java | 98 +++++++ 34 files changed, 1106 insertions(+), 194 deletions(-) create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataCallbackHandler.java create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java create mode 100644 meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java create mode 100644 meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java delete mode 100644 meerkat-common/src/main/java/meerkat/comm/Timestamp.java create mode 100644 meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java create mode 100644 meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java create mode 100644 meerkat-common/src/test/java/meerkat/comm/MessageStreamTest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index dba596b..1a4b62f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -8,7 +8,7 @@ package meerkat.bulletinboard; */ public abstract class BulletinClientWorker { - protected IN payload; // Payload of the job + protected final IN payload; // Payload of the job private int maxRetry; // Number of retries for this job; set to -1 for infinite retries diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java index 727a922..7347f47 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java @@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class MultiServerWorker extends BulletinClientWorker implements Runnable, FutureCallback{ - private List clients; + private final List clients; protected AtomicInteger minServers; // The minimal number of servers the job must be successful on for the job to be completed @@ -26,7 +26,7 @@ public abstract class MultiServerWorker extends BulletinClientWorker futureCallback; + private final FutureCallback futureCallback; /** * Constructor diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 8cac04d..633e495 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -125,7 +125,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ * 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 + * @return the list of Bulletin Board messages that are returned from a server */ @Override public List readMessages(MessageFilterList filterList) { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index e6070a5..ea0e93d 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -6,10 +6,12 @@ import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import meerkat.bulletinboard.workers.singleserver.*; +import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.BulletinBoardClientParams; import meerkat.util.BulletinBoardUtils; +import javax.ws.rs.NotFoundException; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; @@ -31,15 +33,15 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private final int MAX_RETRIES = 11; - protected ListeningScheduledExecutorService executorService; + private ListeningScheduledExecutorService executorService; protected BatchDigest batchDigest; private long lastServerErrorTime; - protected final long failDelayInMilliseconds; + private final long failDelayInMilliseconds; - protected final long subscriptionIntervalInMilliseconds; + private final long subscriptionIntervalInMilliseconds; /** * Notify the client that a job has failed @@ -86,8 +88,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i */ class RetryCallback implements FutureCallback { - private SingleServerWorker worker; - private FutureCallback futureCallback; + private final SingleServerWorker worker; + private final FutureCallback futureCallback; public RetryCallback(SingleServerWorker worker, FutureCallback futureCallback) { this.worker = worker; @@ -128,7 +130,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i */ class PostBatchDataListCallback implements FutureCallback { - private FutureCallback callback; + private final FutureCallback callback; + private AtomicInteger batchDataRemaining; private AtomicBoolean aggregatedResult; @@ -168,7 +171,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i */ class CompleteBatchReadCallback { - private FutureCallback callback; + private final FutureCallback callback; private List batchDataList; private BulletinBoardMessage batchMessage; @@ -176,7 +179,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private AtomicInteger remainingQueries; private AtomicBoolean failed; - public CompleteBatchReadCallback(FutureCallback callback) { + public CompleteBatchReadCallback(FutureCallback callback) { this.callback = callback; @@ -193,11 +196,16 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i if (remainingQueries.decrementAndGet() == 0){ + String batchIdStr = BulletinBoardUtils.findTagWithPrefix(batchMessage, BulletinBoardConstants.BATCH_ID_TAG_PREFIX); + + if (batchIdStr == null){ + callback.onFailure(new CommunicationException("Server returned invalid message with no Batch ID tag")); + } + BeginBatchMessage beginBatchMessage = BeginBatchMessage.newBuilder() .setSignerId(batchMessage.getSig(0).getSignerId()) - .setBatchId(Integer.parseInt( - BulletinBoardUtils.findTagWithPrefix(batchMessage, BulletinBoardConstants.BATCH_ID_TAG_PREFIX))) + .setBatchId(Integer.parseInt(batchIdStr)) .addAllTag(BulletinBoardUtils.removePrefixTags(batchMessage, Arrays.asList(prefixes))) .build(); callback.onSuccess(new CompleteBatch(beginBatchMessage, batchDataList, batchMessage.getSig(0))); @@ -267,7 +275,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i class SubscriptionCallback implements FutureCallback> { private SingleServerReadMessagesWorker worker; - private MessageHandler messageHandler; + private final MessageHandler messageHandler; private MessageFilterList.Builder filterBuilder; @@ -339,7 +347,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Remove all but first DB address String dbAddress = meerkatDBs.get(0); - meerkatDBs = new LinkedList(); + meerkatDBs = new LinkedList<>(); meerkatDBs.add(dbAddress); } @@ -351,7 +359,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(meerkatDBs.get(0), msg, MAX_RETRIES); // Submit worker and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, callback)); // Calculate the correct message ID and return it batchDigest.reset(); @@ -362,8 +370,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private class PostBatchDataCallback implements FutureCallback { - private CompleteBatch completeBatch; - FutureCallback callback; + private final CompleteBatch completeBatch; + private final FutureCallback callback; public PostBatchDataCallback(CompleteBatch completeBatch, FutureCallback callback) { this.completeBatch = completeBatch; @@ -391,8 +399,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private class BeginBatchCallback implements FutureCallback { - private CompleteBatch completeBatch; - FutureCallback callback; + private final CompleteBatch completeBatch; + private final FutureCallback callback; public BeginBatchCallback(CompleteBatch completeBatch, FutureCallback callback) { this.completeBatch = completeBatch; @@ -438,7 +446,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i new SingleServerBeginBatchWorker(meerkatDBs.get(0), beginBatchMessage, MAX_RETRIES); // Submit worker and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, callback)); } @@ -464,7 +472,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i new SingleServerPostBatchWorker(meerkatDBs.get(0), builder.build(), MAX_RETRIES); // Create worker with redundancy 1 and MAX_RETRIES retries - scheduleWorker(worker, new RetryCallback(worker, listCallback)); + scheduleWorker(worker, new RetryCallback<>(worker, listCallback)); // Increment position in batch startPosition++; @@ -502,7 +510,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i new SingleServerCloseBatchWorker(meerkatDBs.get(0), closeBatchMessage, MAX_RETRIES); // Submit worker and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, callback)); } @@ -513,7 +521,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(meerkatDBs.get(0), id, 1); // Submit job and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, callback)); } @@ -524,7 +532,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); // Submit job and create callback - scheduleWorker(worker, new RetryCallback(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, callback)); } @@ -557,8 +565,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i CompleteBatchReadCallback completeBatchReadCallback = new CompleteBatchReadCallback(callback); // Submit jobs with wrapped callbacks - scheduleWorker(messageWorker, new RetryCallback(messageWorker, completeBatchReadCallback.asBulletinBoardMessageListFutureCallback())); - scheduleWorker(batchWorker, new RetryCallback(batchWorker, completeBatchReadCallback.asBatchDataListFutureCallback())); + scheduleWorker(messageWorker, new RetryCallback<>(messageWorker, completeBatchReadCallback.asBulletinBoardMessageListFutureCallback())); + scheduleWorker(batchWorker, new RetryCallback<>(batchWorker, completeBatchReadCallback.asBatchDataListFutureCallback())); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java index 82ca886..ecebc12 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerWorker.java @@ -25,7 +25,7 @@ public abstract class SingleServerWorker extends BulletinClientWorker clients; + private List clients; - BatchDigest batchDigest; + private BatchDigest batchDigest; private final static int POST_MESSAGE_RETRY_NUM = 3; private final static int READ_MESSAGES_RETRY_NUM = 1; @@ -59,7 +59,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple executorService = Executors.newFixedThreadPool(JOBS_THREAD_NUM); - clients = new ArrayList(clientParams.getBulletinBoardAddressCount()); + clients = new ArrayList<>(clientParams.getBulletinBoardAddressCount()); for (String address : clientParams.getBulletinBoardAddressList()){ SingleServerBulletinBoardClient client = @@ -80,7 +80,6 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple * Retry failed DBs * @param msg is the message, * @return the message ID for later retrieval - * @throws CommunicationException */ @Override public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback){ diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java index 4ff96b1..8172e14 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java @@ -31,8 +31,6 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< * It accesses the servers one by one and tries to post the payload to each in turn * The method will only iterate once through the server list * Successful post to a server results in removing the server from the list - * @return The original job, but with a modified server list - * @throws CommunicationException */ public void run() { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java index 68fc020..88b4ac1 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java @@ -14,7 +14,7 @@ import java.util.List; */ public abstract class MultiServerGenericReadWorker extends MultiServerWorker{ - protected Iterator clientIterator; + private final Iterator clientIterator; public MultiServerGenericReadWorker(List clients, int minServers, IN payload, int maxRetry, @@ -32,8 +32,6 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW * This method carries out the actual communication with the servers via HTTP Post * It accesses the servers in a random order until one answers it * Successful retrieval from any server terminates the method and returns the received values; The list is not changed - * @return The original job and the list of messages found in the first server that answered the query - * @throws CommunicationException */ public void run(){ diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java index 517dbdf..748916b 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java @@ -33,8 +33,6 @@ public class MultiServerGetRedundancyWorker extends MultiServerWorker= getClientNumber()){ - succeed(new Float(((float) serversContainingMessage.get()) / ((float) getClientNumber()) )); + succeed(((float) serversContainingMessage.get()) / ((float) getClientNumber())); } } @Override public void onFailure(Throwable t) { - onSuccess(new Float(0.0)); + onSuccess(0.0f); } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java index c56af05..621a828 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java @@ -19,7 +19,7 @@ import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER */ public class SingleServerGenericPostWorker extends SingleServerWorker { - private String subPath; + private final String subPath; public SingleServerGenericPostWorker(String serverAddress, String subPath, T payload, int maxRetry) { super(serverAddress, payload, maxRetry); @@ -37,7 +37,7 @@ public class SingleServerGenericPostWorker extends SingleServerWorker 0){ // Message exists in the server - return new Float(1.0); + return 1.0f; } else { // Message does not exist in the server - return new Float(0.0); + return 0.0f; } } catch (ProcessingException | IllegalStateException e) { diff --git a/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java index c266086..dfccebc 100644 --- a/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java @@ -43,8 +43,8 @@ public class ThreadedBulletinBoardClientIntegrationTest { private static String KEYFILE_PASSWORD1 = "secret"; private static String KEYFILE_PASSWORD3 = "shh"; - public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; - public static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; + private static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + private static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; // Server data @@ -81,7 +81,7 @@ public class ThreadedBulletinBoardClientIntegrationTest { InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); char[] password = KEYFILE_PASSWORD1.toCharArray(); - KeyStore.Builder keyStoreBuilder = null; + KeyStore.Builder keyStoreBuilder; try { keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); @@ -304,11 +304,11 @@ public class ThreadedBulletinBoardClientIntegrationTest { random = new Random(0); // We use insecure randomness in tests for repeatability - List testDB = new LinkedList(); + List testDB = new LinkedList<>(); testDB.add(BASE_URL); bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() - .addBulletinBoardAddress("http://localhost:8081") + .addAllBulletinBoardAddress(testDB) .setMinRedundancy((float) 1.0) .build()); @@ -344,7 +344,6 @@ public class ThreadedBulletinBoardClientIntegrationTest { 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}; BulletinBoardMessage msg; @@ -353,8 +352,6 @@ public class ThreadedBulletinBoardClientIntegrationTest { MessageID messageID; - Comparator msgComparator = new BulletinBoardMessageComparator(); - msg = BulletinBoardMessage.newBuilder() .setMsg(UnsignedBulletinBoardMessage.newBuilder() .addTag("Signature") @@ -398,7 +395,7 @@ public class ThreadedBulletinBoardClientIntegrationTest { ) .build(); - msgList = new LinkedList(); + msgList = new LinkedList<>(); msgList.add(msg); readCallback = new ReadCallback(msgList); diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 59045a2..8d824e7 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -101,6 +101,10 @@ task dbTest(type: Test) { outputs.upToDateWhen { false } } +task manualIntegration(type: Test) { + include '**/*IntegrationTest*' +} + task integrationTest(type: Test) { include '**/*IntegrationTest*' // debug = true diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index a6313b6..b4e2949 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,13 +1,9 @@ package meerkat.bulletinboard.sqlserver; -import java.security.InvalidKeyException; -import java.security.SignatureException; -import java.security.cert.CertificateException; import java.sql.*; import java.util.*; -import com.google.protobuf.ByteString; -import com.google.protobuf.ProtocolStringList; +import com.google.protobuf.*; import meerkat.bulletinboard.*; import meerkat.bulletinboard.sqlserver.mappers.*; @@ -15,6 +11,7 @@ import static meerkat.bulletinboard.BulletinBoardConstants.*; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageOutputStream; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; @@ -27,6 +24,8 @@ import static meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryPro import javax.sql.DataSource; +import meerkat.util.BulletinBoardUtils; +import meerkat.util.TimestampComparator; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -62,8 +61,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ ), INSERT_MSG( - new String[] {"MsgId","Msg"}, - new int[] {Types.BLOB, Types.BLOB} + new String[] {"MsgId","TimeStamp","Msg"}, + new int[] {Types.BLOB, Types.TIMESTAMP, Types.BLOB} ), INSERT_NEW_TAG( @@ -91,6 +90,21 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ new int[] {} ), + COUNT_MESSAGES( + new String[] {}, + new int[] {} + ), + + GET_MESSAGE_STUBS( + new String[] {}, + new int[] {} + ), + + GET_LAST_MESSAGE_ENTRY( + new String[] {}, + new int[] {} + ), + GET_BATCH_MESSAGE_ENTRY( new String[] {"SignerId", "BatchId"}, new int[] {Types.BLOB, Types.INTEGER} @@ -161,7 +175,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ MSG_ID("MsgId", Types.BLOB), SIGNER_ID("SignerId", Types.BLOB), TAG("Tag", Types.VARCHAR), - LIMIT("Limit", Types.INTEGER); + LIMIT("Limit", Types.INTEGER), + TIMESTAMP("TimeStamp", Types.TIMESTAMP); private FilterTypeParam(String paramName, int paramType) { this.paramName = paramName; @@ -191,6 +206,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ case MAX_MESSAGES: return LIMIT; + case BEFORE_TIME: // Go through + case AFTER_TIME: + return TIMESTAMP; + default: return null; } @@ -269,6 +288,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ case MAX_MESSAGES: return messageFilter.getMaxMessages(); + case BEFORE_TIME: // Go through + case AFTER_TIME: + return BulletinBoardUtils.toSQLTimestamp(messageFilter.getTimestamp()); + default: // Unsupported filter type return null; } @@ -316,8 +339,6 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ */ private void createSchema() throws SQLException { - final int TIMEOUT = 20; - for (String command : sqlQueryProvider.getSchemaCreationCommands()) { jdbcTemplate.update(command,(Map) null); } @@ -423,7 +444,6 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Add message to table if needed and store entry number of message. - sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID); Map namedParameters = new HashMap(); namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID); @@ -437,7 +457,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } else{ sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); - namedParameters.put(QueryType.INSERT_MSG.getParamName(1), msg.getMsg().toByteArray()); + + namedParameters.put(QueryType.INSERT_MSG.getParamName(1), BulletinBoardUtils.toSQLTimestamp(msg.getMsg().getTimestamp())); + namedParameters.put(QueryType.INSERT_MSG.getParamName(2), msg.getMsg().toByteArray()); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); @@ -504,37 +526,36 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return postMessage(msg, true); // Perform a post and check the signature for authenticity } - @Override - public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { - BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); + /** + * This is a container class for and SQL string builder and a MapSqlParameterSource to be used with it + */ + class SQLAndParameters { - // SQL length is roughly 50 characters per filter + 50 for the query itself - StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); + public StringBuilder sql; + public MapSqlParameterSource parameters; - MapSqlParameterSource namedParameters; - int paramNum; + public SQLAndParameters(int numOfFilters) { + sql = new StringBuilder(50 * numOfFilters); + parameters = new MapSqlParameterSource(); + } - MessageMapper messageMapper = new MessageMapper(); - SignatureMapper signatureMapper = new SignatureMapper(); + } + + SQLAndParameters getSQLFromFilters(MessageFilterList filterList) { + + SQLAndParameters result = new SQLAndParameters(filterList.getFilterCount()); List filters = new ArrayList(filterList.getFilterList()); - boolean isFirstFilter = true; - Collections.sort(filters, new FilterTypeComparator()); - // Check if Tag/Signature tables are required for filtering purposes - - sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.GET_MESSAGES)); - // Add conditions - - namedParameters = new MapSqlParameterSource(); + boolean isFirstFilter = true; if (!filters.isEmpty()) { - sqlBuilder.append(" WHERE "); + result.sql.append(" WHERE "); - for (paramNum = 0 ; paramNum < filters.size() ; paramNum++) { + for (int paramNum = 0 ; paramNum < filters.size() ; paramNum++) { MessageFilter filter = filters.get(paramNum); @@ -542,15 +563,15 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ if (isFirstFilter) { isFirstFilter = false; } else { - sqlBuilder.append(" AND "); + result.sql.append(" AND "); } } - sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); + result.sql.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); FilterTypeParam filterTypeParam = FilterTypeParam.getFilterTypeParamName(filter.getType()); - namedParameters.addValue( + result.parameters.addValue( filterTypeParam.getParamName() + Integer.toString(paramNum), getParam(filter), filterTypeParam.getParamType(), @@ -560,36 +581,56 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + return result; + + } + + + /** + * Used to retrieve just basic information about messages to allow calculation of checksum + * @param filterList is a filter list that defines which messages the client is interested in + * @return a list of Bulletin Board Messages that contain just the entry number, timestamp and message ID for each message + * The message ID is returned inside the message data field + */ + protected List readMessageStubs(MessageFilterList filterList) { + + StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); + + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.GET_MESSAGE_STUBS)); + + // Get Conditions + + SQLAndParameters sqlAndParameters = getSQLFromFilters(filterList); + + sqlBuilder.append(sqlAndParameters.sql); + // Run query - List msgBuilders = - jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper); + return jdbcTemplate.query(sqlBuilder.toString(), sqlAndParameters.parameters, new MessageStubMapper()); - // Compile list of messages + } - for (BulletinBoardMessage.Builder msgBuilder : msgBuilders) { - // Retrieve signatures + @Override + public void readMessages(MessageFilterList filterList, MessageOutputStream out) throws CommunicationException { - namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_SIGNATURES.getParamName(0), msgBuilder.getEntryNum()); + BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); - List signatures = jdbcTemplate.query( - sqlQueryProvider.getSQLString(QueryType.GET_SIGNATURES), - namedParameters, - signatureMapper); + // SQL length is roughly 50 characters per filter + 50 for the query itself + StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); - // Append signatures - msgBuilder.addAllSig(signatures); + // Check if Tag/Signature tables are required for filtering purposes - // Finalize message and add to message list. + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.GET_MESSAGES)); - resultListBuilder.addMessage(msgBuilder.build()); + // Get conditions - } + SQLAndParameters sqlAndParameters = getSQLFromFilters(filterList); + sqlBuilder.append(sqlAndParameters.sql); - //Combine results and return. - return resultListBuilder.build(); + // Run query and stream the output using a MessageCallbackHandler + + jdbcTemplate.query(sqlBuilder.toString(), sqlAndParameters.parameters, new MessageCallbackHandler(jdbcTemplate, sqlQueryProvider, out)); } @@ -625,9 +666,23 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ .build()) .build(); - BulletinBoardMessageList messageList = readMessages(filterList); + // SQL length is roughly 50 characters per filter + 50 for the query itself + StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); - return (messageList.getMessageList().size() > 0); + // Check if Tag/Signature tables are required for filtering purposes + + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.COUNT_MESSAGES)); + + // Get conditions + + SQLAndParameters sqlAndParameters = getSQLFromFilters(filterList); + sqlBuilder.append(sqlAndParameters.sql); + + // Run query and stream the output using a MessageCallbackHandler + + List count = jdbcTemplate.query(sqlBuilder.toString(), sqlAndParameters.parameters, new LongMapper()); + + return (count.size() > 0) && (count.get(0) > 0); } @@ -767,6 +822,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ .addTag(BATCH_TAG) .addTag(batchIdToTag(batchId)) .setData(message.getSig().getSignerId()) + .setTimestamp(message.getTimestamp()) .build()) .build(); @@ -788,7 +844,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } @Override - public BatchDataList readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException{ + public void readBatch(BatchSpecificationMessage message, MessageOutputStream out) throws CommunicationException, IllegalArgumentException{ // Check that batch is closed if (!isBatchClosed(message.getSignerId(), message.getBatchId())) { @@ -802,9 +858,102 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),message.getStartPosition()); - return BatchDataList.newBuilder() - .addAllData(jdbcTemplate.query(sql, namedParameters, new BatchDataMapper())) - .build(); + jdbcTemplate.query(sql, namedParameters, new BatchDataCallbackHandler(out)); + + } + + /** + * Finds the entry number of the last entry in the database + * @return the entry number, or -1 if no entries are found + */ + protected long getLastMessageEntry() { + + String sql = sqlQueryProvider.getSQLString(QueryType.GET_LAST_MESSAGE_ENTRY); + + List resultList = jdbcTemplate.query(sql, new LongMapper()); + + if (resultList.size() <= 0){ + return -1; + } + + return resultList.get(0); + + } + + /** + * Searches for the latest time of sync of the DB relative to a given query and returns the metadata needed to complete the sync + * The checksum up to (and including) each given timestamp is calculated using bitwise XOR on 8-byte sized blocks of the message IDs + * @param syncQuery contains a succinct representation of states to compare to + * @return the current last entry num and latest time of sync if there is one; -1 as last entry and empty timestamp otherwise + * @throws CommunicationException + */ + @Override + public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException { + + if (syncQuery == null){ + return SyncQueryResponse.newBuilder() + .setLastEntryNum(-1) + .setLastTimeOfSync(com.google.protobuf.Timestamp.getDefaultInstance()) + .build(); + } + + com.google.protobuf.Timestamp lastTimeOfSync = null; + + TimestampComparator timestampComparator = new TimestampComparator(); + + long lastEntryNum = getLastMessageEntry(); + + long checksum = 0; + + Iterator queryIterator = syncQuery.getQueryList().iterator(); + + SingleSyncQuery currentQuery = queryIterator.next(); + + List messageStubs = readMessageStubs(syncQuery.getFilterList()); + + for (BulletinBoardMessage message : messageStubs){ + + // Check for end of current query + if (timestampComparator.compare(message.getMsg().getTimestamp(), currentQuery.getTimeOfSync()) > 0){ + + if (checksum == currentQuery.getChecksum()){ + lastTimeOfSync = currentQuery.getTimeOfSync(); + } else { + break; + } + + if (queryIterator.hasNext()){ + currentQuery = queryIterator.next(); + } else{ + break; + } + + } + + // Advance checksum + + ByteString messageID = message.getMsg().getData(); + + checksum &= messageID.byteAt(0) & messageID.byteAt(1) & messageID.byteAt(2) & messageID.byteAt(3); + + } + + if (checksum == currentQuery.getChecksum()){ + lastTimeOfSync = currentQuery.getTimeOfSync(); + } + + if (lastTimeOfSync == null){ + return SyncQueryResponse.newBuilder() + .setLastEntryNum(-1) + .setLastTimeOfSync(com.google.protobuf.Timestamp.getDefaultInstance()) + .build(); + } else{ + return SyncQueryResponse.newBuilder() + .setLastEntryNum(lastEntryNum) + .setLastTimeOfSync(lastTimeOfSync) + .build(); + } + } @Override diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index 659d9c3..c390048 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -51,6 +51,12 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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"; @@ -61,6 +67,9 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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" @@ -147,6 +156,13 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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); } @@ -190,7 +206,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider public List getSchemaCreationCommands() { List list = new LinkedList(); - list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, Msg BLOB)"); + 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)"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index e3bdef0..f99114e 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -62,6 +62,12 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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}", @@ -69,15 +75,19 @@ public class MySQLQueryProvider implements SQLQueryProvider { case INSERT_MSG: return MessageFormat.format( - "INSERT INTO MsgTable (MsgId, Msg) VALUES(:{0}, :{1})", + "INSERT INTO MsgTable (MsgId, ExactTime, Msg) VALUES(:{0}, :{1}, :{2})", QueryType.INSERT_MSG.getParamName(0), - QueryType.INSERT_MSG.getParamName(1)); + 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" @@ -164,6 +174,13 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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); } @@ -187,6 +204,10 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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); } @@ -212,7 +233,7 @@ public class MySQLQueryProvider implements SQLQueryProvider { List list = new LinkedList(); list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY," - + " MsgId TINYBLOB, Msg BLOB, UNIQUE(MsgId(50)))"); + + " 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))"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataCallbackHandler.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataCallbackHandler.java new file mode 100644 index 0000000..9ad0dc7 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataCallbackHandler.java @@ -0,0 +1,32 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.comm.MessageOutputStream; +import meerkat.protobuf.BulletinBoardAPI.BatchData; +import org.springframework.jdbc.core.RowCallbackHandler; +import org.springframework.jdbc.core.RowMapper; + +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + */ +public class BatchDataCallbackHandler implements RowCallbackHandler { + + private final MessageOutputStream out; + + public BatchDataCallbackHandler(MessageOutputStream out) { + this.out = out; + } + + @Override + public void processRow(ResultSet rs) throws SQLException { + try { + out.writeMessage(BatchData.parseFrom(rs.getBytes(1))); + } catch (IOException e) { + //TODO: Log + } + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java new file mode 100644 index 0000000..bdba241 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java @@ -0,0 +1,80 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.*; +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider.*; +import meerkat.comm.MessageOutputStream; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; +import org.springframework.jdbc.core.RowCallbackHandler; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; + +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + */ +public class MessageCallbackHandler implements RowCallbackHandler { + + NamedParameterJdbcTemplate jdbcTemplate; + SQLQueryProvider sqlQueryProvider; + MessageOutputStream out; + + public MessageCallbackHandler(NamedParameterJdbcTemplate jdbcTemplate, SQLQueryProvider sqlQueryProvider, MessageOutputStream out) { + + this.jdbcTemplate = jdbcTemplate; + this.sqlQueryProvider = sqlQueryProvider; + this.out = out; + + } + + @Override + public void processRow(ResultSet rs) throws SQLException { + + BulletinBoardMessage.Builder result; + + try { + + result = BulletinBoardMessage.newBuilder() + .setEntryNum(rs.getLong(1)) + .setMsg(UnsignedBulletinBoardMessage.parseFrom(rs.getBytes(2))); + + + } catch (InvalidProtocolBufferException e) { + //TODO: log + return; + } + + // Retrieve signatures + + MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource(); + sqlParameterSource.addValue(QueryType.GET_SIGNATURES.getParamName(0), result.getEntryNum()); + + List signatures = jdbcTemplate.query( + sqlQueryProvider.getSQLString(QueryType.GET_SIGNATURES), + sqlParameterSource, + new SignatureMapper()); + + // Append signatures + result.addAllSig(signatures); + + // Finalize message and add to message list. + + try { + + out.writeMessage(result.build()); + + } catch (IOException e) { + + //TODO: log + e.printStackTrace(); + + } + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java new file mode 100644 index 0000000..1f9c459 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java @@ -0,0 +1,31 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; +import meerkat.util.BulletinBoardUtils; +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 MessageStubMapper implements RowMapper { + + @Override + public BulletinBoardMessage mapRow(ResultSet rs, int rowNum) throws SQLException { + + return BulletinBoardMessage.newBuilder() + .setEntryNum(rs.getLong(1)) + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .setData(ByteString.copyFrom(rs.getBytes(2))) + .setTimestamp(BulletinBoardUtils.toTimestampProto(rs.getTimestamp(3))) + .build()) + .build(); + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 766af19..2e4782f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -3,13 +3,10 @@ package meerkat.bulletinboard.webapp; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; +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; @@ -17,12 +14,19 @@ 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.List; +/** + * An implementation of the BulletinBoardServer which functions as a WebApp + */ @Path(BULLETIN_BOARD_SERVER_PATH) public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{ @@ -88,15 +92,39 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL init(); return bulletinBoard.postMessage(msg); } - + + @Override + public void readMessages(MessageFilterList filterList, MessageOutputStream out) throws CommunicationException { + init(); + bulletinBoard.readMessages(filterList, out); + } + + @Path(READ_MESSAGES_PATH) @POST @Consumes(MEDIATYPE_PROTOBUF) - @Produces(MEDIATYPE_PROTOBUF) - @Override - public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { - init(); - return bulletinBoard.readMessages(filterList); + /** + * 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 out = new MessageOutputStream<>(output); + + try { + init(); + bulletinBoard.readMessages(filterList, out); + } catch (CommunicationException e) { + //TODO: Log + out.writeMessage(null); + } + } + + }; + } @Path(BEGIN_BATCH_PATH) @@ -144,15 +172,53 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } + + @Override + public void readBatch(BatchSpecificationMessage message, MessageOutputStream out) { + try { + init(); + bulletinBoard.readBatch(message, out); + } catch (CommunicationException | IllegalArgumentException e) { + System.err.println(e.getMessage()); + } + } + @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 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 BatchDataList readBatch(BatchSpecificationMessage message) { - try { + public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException { + try{ init(); - return bulletinBoard.readBatch(message); + return bulletinBoard.querySync(syncQuery); } catch (CommunicationException | IllegalArgumentException e) { System.err.println(e.getMessage()); return null; diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java index 4b8b586..744a086 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java @@ -4,6 +4,8 @@ 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.*; @@ -18,7 +20,10 @@ 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 { @@ -44,6 +49,16 @@ public class BulletinBoardSQLServerIntegrationTest { 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; @@ -51,7 +66,7 @@ public class BulletinBoardSQLServerIntegrationTest { BulletinBoardMessage msg; MessageFilterList filterList; - BulletinBoardMessageList msgList; + List msgList; // Test writing mechanism @@ -64,6 +79,7 @@ public class BulletinBoardSQLServerIntegrationTest { .addTag("Signature") .addTag("Trustee") .setData(ByteString.copyFrom(b1)) + .setTimestamp(t1) .build()) .addSig(Signature.newBuilder() .setType(SignatureType.DSA) @@ -87,6 +103,7 @@ public class BulletinBoardSQLServerIntegrationTest { .addTag("Vote") .addTag("Trustee") .setData(ByteString.copyFrom(b4)) + .setTimestamp(t2) .build()) .addSig(Signature.newBuilder() .setType(SignatureType.ECDSA) @@ -113,13 +130,20 @@ public class BulletinBoardSQLServerIntegrationTest { ) .build(); - response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF)); - System.err.println(response); - msgList = response.readEntity(BulletinBoardMessageList.class); - System.err.println("List size: " + msgList.getMessageCount()); + InputStream in = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF), InputStream.class); + + MessageInputStream inputStream = + MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BulletinBoardMessage.class); + + msgList = inputStream.asList(); + System.err.println("List size: " + msgList.size()); System.err.println("This is the list:"); - System.err.println(TextFormat.printToString(msgList)); - assert msgList.getMessageCount() == 1; + + for (BulletinBoardMessage message : msgList) { + System.err.println(TextFormat.printToString(message)); + } + + assert msgList.size() == 1; } } diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 86a32de..e33c739 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -1,9 +1,12 @@ package meerkat.bulletinboard; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; +import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyStore; @@ -16,17 +19,23 @@ import java.util.*; import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageInputStream; +import meerkat.comm.MessageOutputStream; +import meerkat.comm.MessageInputStream.MessageInputStreamFactory; import meerkat.crypto.concrete.ECDSASignature; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.util.BulletinBoardUtils; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; public class GenericBulletinBoardServerTest { protected BulletinBoardServer bulletinBoardServer; - private GenericBatchDigitalSignature signers[]; + private GenericBatchDigitalSignature[] signers; private ByteString[] signerIDs; private Random random; @@ -172,7 +181,8 @@ public class GenericBulletinBoardServerTest { for (i = 1; i <= MESSAGE_NUM; i++) { unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder() - .setData(ByteString.copyFrom(data[i - 1])); + .setData(ByteString.copyFrom(data[i - 1])) + .setTimestamp(BulletinBoardUtils.toTimestampProto()); // Add tags based on bit-representation of message number. @@ -232,28 +242,39 @@ public class GenericBulletinBoardServerTest { System.err.println("Starting to test tag and signature mechanism"); long start = threadBean.getCurrentThreadCpuTime(); - List messages; + List messages = new LinkedList<>(); // Check tag mechanism - + for (int i = 0 ; i < TAG_NUM ; i++){ // Retrieve messages having tag i try { - messages = bulletinBoardServer.readMessages( - MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(tags[i]) - .build() - ) - .build() - ) - .getMessageList(); + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(tags[i]) + .build() + ) + .build(); - } catch (CommunicationException e) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + bulletinBoardServer.readMessages(filterList, new MessageOutputStream(outputStream)); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream(new ByteArrayInputStream( + outputStream.toByteArray()), + BulletinBoardMessage.class); + + messages = inputStream.asList(); + + } catch (CommunicationException | IOException e) { + fail(e.getMessage()); + return; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { fail(e.getMessage()); return; } @@ -330,11 +351,26 @@ public class GenericBulletinBoardServerTest { ); try { - messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + bulletinBoardServer.readMessages(filterListBuilder.build(), new MessageOutputStream(outputStream)); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream(new ByteArrayInputStream( + outputStream.toByteArray()), + BulletinBoardMessage.class); + + messages = inputStream.asList(); + } catch (CommunicationException e) { System.err.println("Failed retrieving multi-tag messages from DB: " + e.getMessage()); fail("Failed retrieving multi-tag messages from DB: " + e.getMessage()); return; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | IOException e) { + System.err.println("Falied to read from stream while retrieving multi-tag messages: " + e.getMessage()); + fail("Falied to read from stream while retrieving multi-tag messages: " + e.getMessage()); + return; } expectedMsgCount /= 2; @@ -361,11 +397,26 @@ public class GenericBulletinBoardServerTest { .build()); try { - messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + bulletinBoardServer.readMessages(filterListBuilder.build(), new MessageOutputStream(outputStream)); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream(new ByteArrayInputStream( + outputStream.toByteArray()), + BulletinBoardMessage.class); + + messages = inputStream.asList(); + } catch (CommunicationException e) { System.err.println("Failed retrieving multi-signature message from DB: " + e.getMessage()); fail("Failed retrieving multi-signature message from DB: " + e.getMessage()); return; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | IOException e) { + System.err.println("Falied to read from stream while retrieving multi-signature message: " + e.getMessage()); + fail("Falied to read from stream while retrieving multi-signature message: " + e.getMessage()); + return; } assertThat(messages.size(), is(MESSAGE_NUM / 4)); @@ -388,7 +439,10 @@ public class GenericBulletinBoardServerTest { final int BATCH_ID = 100; - CompleteBatch completeBatch = new CompleteBatch(); + CompleteBatch completeBatch = new CompleteBatch(Timestamp.newBuilder() + .setSeconds(978325) + .setNanos(8097234) + .build()); BoolMsg result; // Create data @@ -429,11 +483,7 @@ public class GenericBulletinBoardServerTest { // Close batch - result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder() - .setBatchId(BATCH_ID) - .setBatchLength(1) - .setSig(completeBatch.getSignature()) - .build()); + result = bulletinBoardServer.closeBatchMessage(completeBatch.getCloseBatchMessage()); assertThat("Was not able to close batch", result.getValue(), is(true)); @@ -457,7 +507,10 @@ public class GenericBulletinBoardServerTest { */ public void testPostBatch() throws CommunicationException, SignatureException { - CompleteBatch completeBatch = new CompleteBatch(); + CompleteBatch completeBatch = new CompleteBatch(Timestamp.newBuilder() + .setSeconds(12345) + .setNanos(1111) + .build()); int currentBatch = completeBatches.size(); BoolMsg result; @@ -523,11 +576,7 @@ public class GenericBulletinBoardServerTest { signers[0].updateContent(completeBatch); completeBatch.setSignature(signers[0].sign()); - result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder() - .setBatchId(currentBatch) - .setBatchLength(tempBatchData.length) - .setSig(completeBatch.getSignature()) - .build()); + result = bulletinBoardServer.closeBatchMessage(completeBatch.getCloseBatchMessage()); assertThat("Could not close batch " + currentBatch, result.getValue(), is(true)); @@ -540,17 +589,32 @@ public class GenericBulletinBoardServerTest { for (CompleteBatch completeBatch : completeBatches) { - List batchDataList = - bulletinBoardServer.readBatch(BatchSpecificationMessage.newBuilder() - .setSignerId(completeBatch.getBeginBatchMessage().getSignerId()) - .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) - .setStartPosition(0) - .build()); + try { - assertThat("Non-matching batch data for batch " + completeBatch.getBeginBatchMessage().getBatchId(), - completeBatch.getBatchDataList().equals(batchDataList), is(true)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + BatchSpecificationMessage batchSpecificationMessage = + BatchSpecificationMessage.newBuilder() + .setSignerId(completeBatch.getBeginBatchMessage().getSignerId()) + .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) + .setStartPosition(0) + .build(); + bulletinBoardServer.readBatch(batchSpecificationMessage, new MessageOutputStream(outputStream)); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream(new ByteArrayInputStream( + outputStream.toByteArray()), + BatchData.class); + + List batchDataList = inputStream.asList(); + + assertThat("Non-matching batch data for batch " + completeBatch.getBeginBatchMessage().getBatchId(), + completeBatch.getBatchDataList().equals(batchDataList), is(true)); + + } catch (IOException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + assertThat("Error reading batch data list from input stream", false); + } } diff --git a/meerkat-common/build.gradle b/meerkat-common/build.gradle index 3783531..a9035b0 100644 --- a/meerkat-common/build.gradle +++ b/meerkat-common/build.gradle @@ -39,6 +39,7 @@ 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' diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java index 6bfc06f..66652f8 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -14,6 +14,7 @@ public interface BulletinBoardConstants { public static final String BEGIN_BATCH_PATH = "/beginbatch"; public static final String POST_BATCH_PATH = "/postbatch"; public static final String CLOSE_BATCH_PATH = "/closebatch"; + public static final String SYNC_QUERY_PATH = "/syncquery"; // Other Constants diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index cbf06ff..0b279c2 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -1,9 +1,9 @@ package meerkat.bulletinboard; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageOutputStream; import meerkat.protobuf.BulletinBoardAPI.*; -import java.util.List; /** * Created by Arbel on 07/11/15. @@ -32,10 +32,10 @@ public interface BulletinBoardServer{ /** * Read all messages posted matching the given filter * @param filterList return only messages that match the filters (empty list or null means no filtering) - * @return + * @param out is an output stream into which the matching messages are written * @throws CommunicationException on DB connection error */ - public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException; + public void readMessages(MessageFilterList filterList, MessageOutputStream out) throws CommunicationException; /** * Informs server about a new batch message @@ -71,11 +71,20 @@ public interface BulletinBoardServer{ /** * 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 - * @return an ordered list of batch messages starting from the specified start position (if given) or from the beginning (if omitted) + * @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 BatchDataList readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException; + public void readBatch(BatchSpecificationMessage message, MessageOutputStream out) throws CommunicationException, IllegalArgumentException; + + + /** + * 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 diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 227c7ca..14e87e7 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -1,5 +1,6 @@ package meerkat.bulletinboard; +import com.google.protobuf.Timestamp; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.*; import meerkat.util.BulletinBoardMessageComparator; @@ -17,6 +18,7 @@ public class CompleteBatch { private BeginBatchMessage beginBatchMessage; private List batchDataList; private Signature signature; + private Timestamp timestamp; public CompleteBatch() { batchDataList = new LinkedList(); @@ -37,6 +39,16 @@ public class CompleteBatch { signature = newSignature; } + public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List newDataList, Signature newSignature, Timestamp timestamp) { + this(newBeginBatchMessage, newDataList, newSignature); + this.timestamp = timestamp; + } + + public CompleteBatch(Timestamp timestamp) { + this(); + this.timestamp = timestamp; + } + public BeginBatchMessage getBeginBatchMessage() { return beginBatchMessage; } @@ -49,11 +61,16 @@ public class CompleteBatch { return signature; } + public Timestamp getTimestamp() { + return timestamp; + } + public CloseBatchMessage getCloseBatchMessage() { return CloseBatchMessage.newBuilder() .setBatchId(getBeginBatchMessage().getBatchId()) .setBatchLength(getBatchDataList().size()) .setSig(getSignature()) + .setTimestamp(getTimestamp()) .build(); } @@ -73,6 +90,10 @@ public class CompleteBatch { signature = newSignature; } + public void setTimestamp(Timestamp timestamp) { + this.timestamp = timestamp; + } + @Override public boolean equals(Object other) { @@ -105,6 +126,13 @@ public class CompleteBatch { result = result && signature.equals(otherBatch.getSignature()); } + if (timestamp == null) { + if (otherBatch.getTimestamp() != null) + return false; + } else { + result = result && timestamp.equals(otherBatch.getTimestamp()); + } + return result; } diff --git a/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java new file mode 100644 index 0000000..33deb3f --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java @@ -0,0 +1,64 @@ +package meerkat.comm; + +import com.google.protobuf.Message; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + * A input stream of Protobuf messages + */ +public class MessageInputStream{ + + private T.Builder builder; + + private InputStream in; + + MessageInputStream(InputStream in, Class type) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + this.in = in; + this.builder = (T.Builder) type.getMethod("newBuilder").invoke(type); + } + + /** + * Factory class for actually creating a MessageInputStream + */ + public static class MessageInputStreamFactory { + + public static MessageInputStream createMessageInputStream(InputStream in, Class type) + throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + return new MessageInputStream<>(in, type); + + } + + } + + public T readMessage() throws IOException{ + + builder.clear(); + builder.mergeDelimitedFrom(in); + return (T) builder.build(); + + } + + public boolean isAvailable() throws IOException { + return (in.available() > 0); + } + + public List asList() throws IOException{ + + List list = new LinkedList<>(); + + while (isAvailable()){ + list.add(readMessage()); + } + + return list; + + } + +} diff --git a/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java b/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java new file mode 100644 index 0000000..b55bc8e --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java @@ -0,0 +1,24 @@ +package meerkat.comm; + +import com.google.protobuf.Message; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + * An output stream of Protobuf messages + */ +public class MessageOutputStream { + + private OutputStream out; + + public MessageOutputStream(OutputStream out) throws IOException { + this.out = out; + } + + public void writeMessage(T message) throws IOException { + message.writeDelimitedTo(out); + } + +} diff --git a/meerkat-common/src/main/java/meerkat/comm/Timestamp.java b/meerkat-common/src/main/java/meerkat/comm/Timestamp.java deleted file mode 100644 index 6c63854..0000000 --- a/meerkat-common/src/main/java/meerkat/comm/Timestamp.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.comm; - -/** - * Created by talm on 24/10/15. - */ -public class Timestamp { -} diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java new file mode 100644 index 0000000..5ca3e0b --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java @@ -0,0 +1,98 @@ +package meerkat.util; + +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.BulletinBoardAPI.*; +import com.google.protobuf.Timestamp; + +import java.math.BigInteger; +import java.security.SignatureException; +import java.util.Arrays; +import java.util.Random; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + * This class contains methods used to generate random Bulletin Board Messages + */ +public class BulletinBoardMessageGenerator { + + private Random random; + + public BulletinBoardMessageGenerator(Random random) { + this.random = random; + } + + private byte randomByte(){ + return (byte) random.nextInt(); + } + + private String randomString(){ + return new BigInteger(130, random).toString(32); + } + + /** + * Generates a complete instance of a BulletinBoardMessage + * @param signers contains the (possibly multiple) credentials required to sign the message + * @param timestamp contains the time used in the message + * @param dataSize is the length of the data contained in the message + * @param tagNumber is the number of tags to generate + * @return a random, signed Bulletin Board Message containing random data and tags and the given timestamp + */ + + public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, Timestamp timestamp, int dataSize, int tagNumber) + throws SignatureException { + + // Generate random data. + + byte[] data = new byte[dataSize]; + String[] tags = new String[tagNumber]; + + for (int i = 0; i < dataSize; i++) { + data[i] = randomByte(); + } + + for (int i = 0; i < tagNumber; i++) { + tags[i] = randomString(); + } + + UnsignedBulletinBoardMessage unsignedMessage = + UnsignedBulletinBoardMessage.newBuilder() + .setData(ByteString.copyFrom(data)) + .setTimestamp(timestamp) + .addAllTag(Arrays.asList(tags)) + .build(); + + BulletinBoardMessage.Builder messageBuilder = + BulletinBoardMessage.newBuilder() + .setMsg(unsignedMessage); + + for (int i = 0 ; i < signers.length ; i++) { + signers[i].updateContent(unsignedMessage); + messageBuilder.addSig(signers[i].sign()); + } + + return messageBuilder.build(); + + } + + /** + * Generates a complete instance of a BulletinBoardMessage + * @param signers contains the (possibly multiple) credentials required to sign the message + * @param dataSize is the length of the data contained in the message + * @param tagNumber is the number of tags to generate + * @return a random, signed Bulletin Board Message containing random data, tags and timestamp + */ + + public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, int dataSize, int tagNumber) + throws SignatureException { + + Timestamp timestamp = Timestamp.newBuilder() + .setSeconds(random.nextLong()) + .setNanos(random.nextInt()) + .build(); + + return generateRandomMessage(signers, timestamp, dataSize, tagNumber); + + } + +} diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java index b19bab3..d8b362c 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java @@ -62,4 +62,46 @@ public class BulletinBoardUtils { } + /** + * This method creates a Timestamp Protobuf from a time specification + * @param timeInMillis is the time to encode since the Epoch time in milliseconds + * @return a Timestamp Protobuf encoding of the given time + */ + public static com.google.protobuf.Timestamp toTimestampProto(long timeInMillis) { + + return com.google.protobuf.Timestamp.newBuilder() + .setSeconds(timeInMillis / 1000) + .setNanos((int) ((timeInMillis % 1000) * 1000000)) + .build(); + + } + + /** + * This method creates a Timestamp Protobuf from the current system time + * @return a Timestamp Protobuf encoding of the current system time + */ + public static com.google.protobuf.Timestamp toTimestampProto() { + + return toTimestampProto(System.currentTimeMillis()); + + } + + /** + * This method converts an SQL Timestamp object into a Protobuf Timestamp object + * @param sqlTimestamp is the SQL Timestamp + * @return an equivalent Protobuf Timestamp + */ + public static com.google.protobuf.Timestamp toTimestampProto(java.sql.Timestamp sqlTimestamp) { + return toTimestampProto(sqlTimestamp.getTime()); + } + + /** + * This method converts a Protobuf Timestamp object into an SQL Timestamp object + * @param protoTimestamp is the Protobuf Timestamp + * @return an equivalent SQL Timestamp + */ + public static java.sql.Timestamp toSQLTimestamp(com.google.protobuf.Timestamp protoTimestamp) { + return new java.sql.Timestamp(protoTimestamp.getSeconds() * 1000 + protoTimestamp.getNanos() / 1000000); + } + } diff --git a/meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java b/meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java new file mode 100644 index 0000000..1dc207b --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java @@ -0,0 +1,30 @@ +package meerkat.util; + +import com.google.protobuf.Timestamp; + +import java.util.Comparator; + +/** + * Created by Arbel Deutsch Peled on 20-Feb-16. + */ +public class TimestampComparator implements Comparator { + + @Override + public int compare(Timestamp o1, Timestamp o2) { + + if (o1.getSeconds() != o2.getSeconds()){ + + return o1.getSeconds() > o2.getSeconds() ? 2 : -2; + + } else if (o1.getNanos() != o2.getNanos()){ + + return o1.getNanos() > o2.getNanos() ? 1 : -1; + + } else{ + + return 0; + + } + + } +} diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index b86debd..fd95503 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -5,6 +5,7 @@ package meerkat; option java_package = "meerkat.protobuf"; import 'meerkat/crypto.proto'; +import 'google/protobuf/timestamp.proto'; message BoolMsg { bool value = 1; @@ -21,11 +22,14 @@ message MessageID { } message UnsignedBulletinBoardMessage { - // Optional tags describing message + // 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 = 2; + bytes data = 3; } message BulletinBoardMessage { @@ -38,6 +42,7 @@ message BulletinBoardMessage { // Signature of message (and tags), excluding the entry number. repeated meerkat.Signature sig = 3; + } message BulletinBoardMessageList { @@ -53,11 +58,13 @@ enum FilterType { 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 = 6; // Return at most some specified number of messages + MAX_MESSAGES = 8; // Return at most some specified number of messages } message MessageFilter { @@ -69,6 +76,7 @@ message MessageFilter { int64 entry = 3; string tag = 4; int64 maxMessages = 5; + google.protobuf.Timestamp timestamp = 6; } } @@ -89,9 +97,10 @@ message BeginBatchMessage { // 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 - meerkat.Signature sig = 3; // Signature on the (ordered) batch messages + 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 @@ -117,4 +126,34 @@ 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 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; + } \ No newline at end of file diff --git a/meerkat-common/src/test/java/meerkat/comm/MessageStreamTest.java b/meerkat-common/src/test/java/meerkat/comm/MessageStreamTest.java new file mode 100644 index 0000000..58dc7c1 --- /dev/null +++ b/meerkat-common/src/test/java/meerkat/comm/MessageStreamTest.java @@ -0,0 +1,98 @@ +package meerkat.comm; + +import com.google.protobuf.*; +import meerkat.comm.MessageInputStream.MessageInputStreamFactory; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; +import meerkat.util.BulletinBoardMessageComparator; +import org.junit.Test; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + * Tests for MessageInputStream and MessageOutputStream classes + */ +public class MessageStreamTest { + + @Test + public void testWithBulletinBoardMessages() { + + MessageOutputStream out; + MessageInputStream in; + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + BulletinBoardMessageComparator comparator = new BulletinBoardMessageComparator(); + + 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}; + + try { + + out = new MessageOutputStream<>(stream); + + } catch (IOException e) { + + System.err.println(e.getMessage()); + assertThat("Error creating streams: " + e.getMessage(), false); + return; + + } + + + + BulletinBoardMessage message = BulletinBoardMessage.newBuilder() + .setEntryNum(1) + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .setData(ByteString.copyFrom(b1)) + .addTag("Test") + .addTag("1234") + .setTimestamp(com.google.protobuf.Timestamp.newBuilder() + .setSeconds(19823451) + .setNanos(2134) + .build()) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setSignerId(ByteString.copyFrom(b2)) + .setData(ByteString.copyFrom(b3)) + .build()) + .build(); + + try { + + out.writeMessage(message); + + } catch (IOException e) { + + System.err.println(e.getMessage()); + assertThat("Error writing message: " + e.getMessage(), false); + + } + + try { + + in = MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(stream.toByteArray()), + BulletinBoardMessage.class); + + assertThat("Retrieved message was not identical to send message", comparator.compare(message, in.readMessage()), is(equalTo(0))); + + } catch (IOException e) { + + System.err.println(e.getMessage()); + assertThat("Error reading message: " + e.getMessage(), false); + + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + System.err.println(e.getMessage()); + assertThat("Error creating input stream " + e.getMessage(), false); + } + + } + +} From 0f7dbe3d50f1d20554d2d9ca7c58888b5943c375 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 23 Feb 2016 19:02:49 +0200 Subject: [PATCH 021/106] SDKG tested for non coruppted parties --- .../main/java/Communication/MailHandler.java | 16 +- .../src/main/java/Communication/User.java | 4 +- .../VerifiableSecretSharing.java | 92 ++---- ...VerifiableSecretSharingMessageHandler.java | 40 --- .../DistributedKeyGeneration.java | 242 +++++++-------- ...istributedKeyGenerationMessageHandler.java | 161 ---------- .../DistributedKeyGenerationUserImpl.java | 288 ++++++++++++++++++ .../SecureDistributedKeyGeneration.java | 112 ++++--- ...istributedKeyGenerationMessageHandler.java | 61 ---- ...ecureDistributedKeyGenerationUserImpl.java | 138 +++++++++ .../ShamirSecretSharing/SecretSharing.java | 44 +-- .../SecretSharingMessageHandler.java | 47 --- .../DistributedKeyGenerationUser.java | 13 + .../java/UserInterface/SecretSharingUser.java | 14 + .../VerifiableSecretSharingUser.java | 16 + .../VerifiableSecretSharingTest.java | 9 +- .../java/JointFeldmanProtocol/DKGTest.java | 31 +- .../src/test/java/SDKGTest.java | 113 +++++++ .../SecretSharingTest.java | 8 +- .../src/main/proto/meerkat/DKGMessages.proto | 1 + 20 files changed, 842 insertions(+), 608 deletions(-) delete mode 100644 destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java delete mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java delete mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java delete mode 100644 destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java create mode 100644 destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java create mode 100644 destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java create mode 100644 destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java create mode 100644 destributed-key-generation/src/test/java/SDKGTest.java diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/Communication/MailHandler.java index c70032f..618ba4f 100644 --- a/destributed-key-generation/src/main/java/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MailHandler.java @@ -9,14 +9,10 @@ import meerkat.protobuf.DKGMessages; public class MailHandler { private MessageHandler messageHandler; - public MailHandler(MessageHandler messageHandler){ this.messageHandler = messageHandler; } - public MessageHandler getMessageHandler(){ - return messageHandler; - } public void handel(DKGMessages.Mail mail) throws InvalidProtocolBufferException { switch (mail.getType()){ @@ -36,8 +32,20 @@ public class MailHandler { DKGMessages.ComplaintMessage complaintMessage = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); messageHandler.handelComplaintMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,complaintMessage); break; + case DOUBLE: + DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + messageHandler.handelDoubleSecretMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,doubleSecretMessage); default: break; } } + + + public MessageHandler getMessageHandler(){ + return messageHandler; + } + + public void setMessageHandler(MessageHandler messageHandler) { + this.messageHandler = messageHandler; + } } diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java index e28347c..2de1ba1 100644 --- a/destributed-key-generation/src/main/java/Communication/User.java +++ b/destributed-key-generation/src/main/java/Communication/User.java @@ -33,8 +33,8 @@ public class User{ network.sendBroadcast(this,type,message); } - public MessageHandler getMessageHandler(){ - return mailHandler.getMessageHandler(); + public void setMessageHandler(MessageHandler messageHandler) { + mailHandler.setMessageHandler(messageHandler); } public int getID() { diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 796aaa9..51ae86e 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -1,12 +1,11 @@ package FeldmanVerifiableSecretSharing; -import Communication.Network; -import Communication.User; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; + import java.util.Arrays; + +import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; @@ -21,31 +20,23 @@ import java.util.Random; * */ public class VerifiableSecretSharing extends SecretSharing { - protected final Zpstar zpstar; + protected final Group group; protected final BigInteger g; // public generator of group - private final BigInteger y; // y = g ^ x - protected final BigInteger[] commitments; + protected final BigInteger[] commitmentsArray; /** - * @param p a large prime - * @param q a large prime dividing p - 1. + * @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 Zp*. + * 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 x, Random random, BigInteger p, BigInteger q, BigInteger g - , User user) { - super(t, n, x, random,q,user); + public VerifiableSecretSharing(int t, int n, BigInteger x, Random random, BigInteger q, BigInteger g + , Group group) { + super(t, n, x, random,q); this.g = g; - this.zpstar = new Zpstar(p); - assert (zpstar.contains(g)); - assert (p.subtract(BigInteger.ONE).mod(q).equals(BigInteger.ZERO)); // assert p - 1 % q == 0 - this.commitments = generateCommitments(); - this.y = zpstar.multiply(g,x); - } - - public VerifiableSecretSharing(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g - , Network network) { - this(t,n,x,random,p,q,g,network.connect(new VerifiableSecretSharingMessageHandler(t))); + this.group = group; + assert (this.group.contains(g)); + this.commitmentsArray = generateCommitments(); } /** @@ -57,7 +48,7 @@ public class VerifiableSecretSharing extends SecretSharing { BigInteger[] coefficients = polynomial.getCoefficients(); BigInteger[] commitments = new BigInteger[coefficients.length]; for (int i = 0 ; i < commitments.length;i++){ - commitments[i] = zpstar.multiply(g,coefficients[i]); + commitments[i] = group.multiply(g,coefficients[i]); } return commitments; } @@ -65,16 +56,16 @@ public class VerifiableSecretSharing extends SecretSharing { /** * @param j share holder id * @param commitments - * @param zpstar + * @param group * - * @return product of commitments[j] ^ (i ^ j) == g ^ polynomial(i) + * @return product of commitmentsArray[j] ^ (i ^ j) == g ^ polynomial(i) */ - public static BigInteger verify(int j,BigInteger[] commitments,Zpstar zpstar) { - BigInteger v = zpstar.zero(); + public static BigInteger verify(int j,BigInteger[] commitments,Group group) { + BigInteger v = group.zero(); BigInteger power = BigInteger.ONE; BigInteger J = BigInteger.valueOf(j); for (int k = 0 ; k < commitments.length ; k ++){ - v = zpstar.add(v,zpstar.multiply(commitments[k],power)); + v = group.add(v,group.multiply(commitments[k],power)); power = power.multiply(J); } return v; @@ -91,49 +82,18 @@ public class VerifiableSecretSharing extends SecretSharing { /** * getter - * @return zpstar + * @return group */ - public Zpstar getZpstar(){ - return zpstar; + public Group getGroup(){ + return group; } /** * getter - * @return public value of this + * @return copy of commitmentsArray */ - public BigInteger getY(){ - return y; + public BigInteger[] getCommitmentsArray() { + return Arrays.copyOf(commitmentsArray, commitmentsArray.length); } - /** - * getter - * @return copy of commitments - */ - public BigInteger[] getCommitments() { - return Arrays.copyOf(commitments,commitments.length); - } - - public DKGMessages.CommitmentMessage[] prepareCommitmentMessages(){ - DKGMessages.CommitmentMessage[] commitmentMessages = new DKGMessages.CommitmentMessage[t + 1]; - for (int k = 0; k <= t ; k ++) { - commitmentMessages[k] = DKGMessages.CommitmentMessage.newBuilder() - .setK(k) - .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) - .build(); - } - return commitmentMessages; - } - - protected void computeAndSendCommitments(){ - DKGMessages.CommitmentMessage[] commitmentMessages = prepareCommitmentMessages(); - for (int k = 0; k <= t ; k ++){ - user.broadcast(DKGMessages.Mail.Type.COMMITMENT,commitmentMessages[k]); - } - } - - @Override - public void run() { - super.run(); - computeAndSendCommitments(); - } } diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java deleted file mode 100644 index bfa23e5..0000000 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingMessageHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package FeldmanVerifiableSecretSharing; - -import Communication.Network; -import ShamirSecretSharing.SecretSharingMessageHandler; -import meerkat.protobuf.DKGMessages; - - -import java.math.BigInteger; -import java.util.Arrays; - -/** - * Created by Tzlil on 2/16/2016. - */ -public class VerifiableSecretSharingMessageHandler extends SecretSharingMessageHandler { - - private final BigInteger[] commitments; - - public VerifiableSecretSharingMessageHandler(int t) { - this.commitments = new BigInteger[t + 1]; - } - - public static BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ - return new BigInteger(commitmentMessage.getCommitment().toByteArray()); - } - - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - if(isBroadcast) { // receive in broadcast only - commitments[commitmentMessage.getK()] = extractCommitment(commitmentMessage); - } - } - - public BigInteger[] getCommitments() { - return commitments; - } - - public BigInteger getY(){ - return commitments[0]; - } -} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java index a9bd311..bf789f1 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -1,156 +1,138 @@ package JointFeldmanProtocol; -import Communication.Network; import Communication.User; import ShamirSecretSharing.Polynomial; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages.*; -import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; +import java.util.Arrays; import java.util.HashSet; import java.util.Random; import java.util.Set; -import java.util.Arrays; /** * Created by Tzlil on 2/5/2016. * * an implementation of a version of Pedersen's distributed key generation protocol */ -public class DistributedKeyGeneration extends VerifiableSecretSharing implements Runnable{ +public class DistributedKeyGeneration extends VerifiableSecretSharing{ - private final int id; + protected final int id; + protected Polynomial.Point[] shares; - private final Set QUAL; // set of all non-disqualified parties - private final BigInteger[] finalCommitments; // public verification values - - private Polynomial.Point share; // final share of the secrete - private BigInteger y; // final public value - - private final DistributedKeyGenerationMessageHandler handler; - - public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g - , User user) { - super(t, n, zi, random, p, q, g,user); - this.handler = (DistributedKeyGenerationMessageHandler) user.getMessageHandler(); - this.id = user.getID(); - this.QUAL = new HashSet(); - this.finalCommitments = new BigInteger[t + 1]; - Arrays.fill(this.finalCommitments,zpstar.zero()); - } - public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g - , Network network) { - this(t,n,zi,random,p,q,g,network.connect(new DistributedKeyGenerationMessageHandler(t,n,g,new Zpstar(p)))); + public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g + , Group group, int id) { + super(t, n, zi, random, q, g,group); + this.id = id; + this.shares = null; } /** - * use for simulate real distributed protocol + * stage1.1 according to the protocol + * Pi broadcasts Aik for k = 0,...,t. */ - @Override - public void run() { - user.getReceiverThread().start(); - stage1(); - stage2(); - stage3(); - stage4(); - user.getReceiverThread().interrupt(); + public void broadcastCommitments(User user){ + broadcastCommitments(user,commitmentsArray); + } + + public void broadcastCommitments(User user, BigInteger[] commitments){ + CommitmentMessage commitmentMessage; + for (int k = 0; k <= t ; k++){ + commitmentMessage = CommitmentMessage.newBuilder() + .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) + .setK(k) + .build(); + user.broadcast(Mail.Type.COMMITMENT, commitmentMessage); + } + } + + public void sendSecret(User user, int j){ + SecretMessage.Point secret = getShare(j).asMessage(); + user.send(j, Mail.Type.DOUBLE,SecretMessage.newBuilder().setSecret(secret).build()); } /** - * 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. + * stage1.2 according to the protocol + * Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj. */ - protected void stage1(){ - super.run(); - while (!handler.isStage1Complete()){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing + public void sendSecrets(User user){ + for (int j = 1; j <= n ; j++){ + if(j != id){ + sendSecret(user,j); } } } + public boolean isValidSecret(int j,BigInteger[] commitments,int i){ + Polynomial.Point secret = shares[j - 1]; + return isValidSecret(secret,commitments,i); + } + + public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int i){ + BigInteger v = verify(i,commitments,group); + return group.multiply(g,secret.y).equals(v); + } + /** * stage2 according to the protocol * Pj verifies all the shares he received (using isValidSecret) * if check fails for an index i, Pj broadcasts a complaint against Pi. - * Pj broadcasts yj value at the end of this stage */ - private void stage2(){ + public void broadcastComplains(User user, BigInteger[][]commitmentsTable){ ComplaintMessage complaint; - for (int i = 1; i <= n ; i++ ){ - if(id != i && !handler.isValidSecret(i)) { - //message = new Message(Type.Complaint, j) - complaint = ComplaintMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(Mail.Type.COMPLAINT,complaint); - } - } - //broadcast done message after all complaints - DoneMessage doneMessage = DoneMessage.newBuilder().build(); - user.broadcast(Mail.Type.DONE,doneMessage); - - while (!handler.isStage2Complete()){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing + for (int j = 1; j <= n ; j++ ){ + if(j != id) { + if (!isValidSecret(j,commitmentsTable[j - 1],id)) { + //message = new Message(Type.Complaint, j) + complaint = ComplaintMessage.newBuilder() + .setId(j) + .build(); + user.broadcast(Mail.Type.COMPLAINT, complaint); + } } } } - - protected void answerComplaint(int j){ + public void broadcastComplaintAnswer(User user, int j){ user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() .setSecret(getShare(j).asMessage()) .build()); } + /** - * stage3 according to the protocol - * 1. if more than t players complain against a player Pi he is disqualified. - * 2. Pi broadcasts the share Sij for each complaining player Pj. - * 3. if any of the revealed shares fails the verification test, player Pi is disqualified. - * 4. set QUAL to be the set of non-disqualified players. + * stage3.1 according to the protocol + * if more than t players complain against a player Pi he is disqualified. */ - private void stage3(){ - DistributedKeyGenerationMessageHandler.ComplainState[][] complainStates = handler.getComplainStates(); - // broadcasts Sij for each complaint against Pid - for (int j = 1; j <= complainStates[id - 1].length; j++) { - switch (complainStates[id - 1][j - 1]) { + public void answerAllComplainingPlayers(User user, DistributedKeyGenerationUserImpl.ComplainState[] complains){ + for (int j = 1; j <= n ; j++) { + switch (complains[j - 1]) { case Waiting: - answerComplaint(j); + broadcastComplaintAnswer(user,j); break; default: break; } } + } - // wait until there is no complaint waiting for answer - for (int i = 0; i < complainStates.length; i++){ - for (int j = 0; j < complainStates[i].length; j++){ - while (complainStates[i][j].equals(DistributedKeyGenerationMessageHandler.ComplainState.Waiting)){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - // add each non-disqualified player to QUAL + /** + * 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 calcQUAL(DistributedKeyGenerationUserImpl.ComplainState[][] complains){ + Set QUAL = new HashSet(); boolean nonDisqualified; int counter; - for (int i = 1; i <= complainStates.length; i++){ + for (int i = 1; i <= complains.length; i++){ nonDisqualified = true; counter = 0; - for (int j = 1; j <= complainStates[i - 1].length; j++){ - switch (complainStates[i - 1][j - 1]) { + for (int j = 1; j <= complains[i - 1].length; j++){ + switch (complains[i - 1][j - 1]) { case Non: break; case NonDisqualified: @@ -165,52 +147,54 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing implements QUAL.add(i); } } + return QUAL; } /** - * 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 + * stage4.1 according to the protocol + * public value y is computed as y = multiplication of yi mod p for i in QUAL */ - private void stage4(){ - this.y = zpstar.zero(); + public BigInteger calcY(BigInteger[] ys,Set QUAL){ + BigInteger y = group.zero(); for (int i : QUAL) { - this.y = zpstar.add(this.y , handler.getY(i)); + y = group.add(y , ys[i - 1]); } - - BigInteger[] commitments; - - for (int i : QUAL) { - commitments = handler.getCommitments(i); - for (int k = 0; k <= t; k++){ - this.finalCommitments[k] = zpstar.add(this.finalCommitments[k],commitments[k]); - } - } - - BigInteger xj = BigInteger.ZERO; - for (int i : QUAL) { - if( i == id){ - xj = xj.add(super.getShare(i).y); - }else{ - xj = xj.add(handler.getShare(i).y); - } - } - this.share = new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); - } - - @Override - public BigInteger getY() { return y; } - @Override - public BigInteger[] getCommitments() { - return Arrays.copyOf(finalCommitments, finalCommitments.length); + /** + * 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 BigInteger[] calcCommitments(BigInteger[][] commitmentsTable,Set QUAL){ + BigInteger[] commitments = new BigInteger[t + 1]; + Arrays.fill(commitments,group.zero()); + for (int i : QUAL) { + for (int k = 0; k <= t; k++){ + commitments[k] = group.add(commitments[k],commitmentsTable[i - 1][k]); + } + } + return commitments; } - public Polynomial.Point getShare() { - return share; + /** + * stage4.3 according to the protocol + * Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL + */ + public Polynomial.Point calcShare(Polynomial.Point[] shares,Set QUAL){ + BigInteger xj = BigInteger.ZERO; + for (int i : QUAL) { + xj = xj.add(shares[i - 1].y); + } + return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); + } + + public int getId() { + return id; + } + + public void setShares(Polynomial.Point[] shares){ + this.shares = shares; } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java deleted file mode 100644 index 2314469..0000000 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMessageHandler.java +++ /dev/null @@ -1,161 +0,0 @@ -package JointFeldmanProtocol; - -import Communication.MessageHandler; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharingMessageHandler; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharingMessageHandler; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.concrete.Zpstar; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 2/16/2016. - */ -public class DistributedKeyGenerationMessageHandler implements MessageHandler { - - protected enum ComplainState{ - Non, Waiting,Disqualified,NonDisqualified - } - - protected final VerifiableSecretSharingMessageHandler[] vssHandlers; - protected final ComplainState[][] complainStates; // complainStates[i][j] == state of Pj's complaint against Pi - protected final BigInteger g; - protected final Zpstar zpstar; - protected final int n; - private final boolean[] doneFlags; - - public DistributedKeyGenerationMessageHandler(int t, int n, BigInteger g, Zpstar zpstar) { - this.g = g; - this.zpstar = zpstar; - this.n = n; - this.doneFlags = new boolean[n]; - this.vssHandlers = new VerifiableSecretSharingMessageHandler[n]; - for (int i = 1; i <= n ; i++){ - vssHandlers[i - 1] = new VerifiableSecretSharingMessageHandler(t); - } - this.complainStates = new ComplainState[n][n]; - for (int i = 0; i < n; i ++){ - for (int j = 0 ; j < n ; j ++) - this.complainStates[i][j] = ComplainState.Non; - } - } - - /** - * @return true iff all shares and commitments were received - */ - protected boolean isStage1Complete(){ - for (int i = 1 ; i <= n ; i++){ - if(vssHandlers[i - 1].getShare() == null) - return false; - } - - BigInteger[] commitments; - for (int i = 0; i < vssHandlers.length; i++){ - commitments = vssHandlers[i].getCommitments(); - for (int j = 0; j < commitments.length; j++){ - if(commitments[j] == null) - return false; - } - } - return true; - } - - /** - * @return true iff all flags in doneFlags are true - */ - protected boolean isStage2Complete() { - for (int j = 0; j < n ; j++) { - if(!doneFlags[j]) - return false; - } - return true; - } - - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { - if(isBroadcast){ - int i = complaintMessage.getId(); - int j = sender; - switch (complainStates[i - 1][j - 1]){ - case Non: - complainStates[i - 1][j - 1] = ComplainState.Waiting; - break; - default: - break; - } - } - } - - @Override - public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { - if(isBroadcast) - this.doneFlags[sender - 1] = true; - } - - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - vssHandlers[sender - 1].handelCommitmentMessage(sender, isBroadcast, commitmentMessage); - } - - - /** - * @param secret - * @param i - * @return g ^ Sij == verify(j,Ai,zpstar) (mod p) - */ - private boolean isValidSecret(Polynomial.Point secret, int i){ - int j = secret.x.intValue(); - BigInteger[] commitments = vssHandlers[i - 1].getCommitments(); - return zpstar.multiply(g,secret.y).equals(VerifiableSecretSharing.verify(j,commitments,zpstar)); - } - - protected boolean isValidSecret(int i){ - return isValidSecret(getShare(i),i); - } - - @Override - public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { - vssHandlers[sender - 1].handelSecretMessage(sender, isBroadcast, secretMessage); - if(isBroadcast){ - Polynomial.Point secret = SecretSharingMessageHandler.extractSecret(secretMessage); - int i = sender; - int j = secret.x.intValue(); - switch (complainStates[i - 1][j - 1]){ - case Waiting: - if(isValidSecret(secret,i)){ - complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; - }else{ - complainStates[i - 1][j - 1] = ComplainState.Disqualified; - } - break; - default: - break; - } - } - } - - @Override - public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - // ignore - } - - - protected ComplainState[][] getComplainStates() { - return complainStates; - } - - protected BigInteger getY(int i){ - return vssHandlers[i - 1].getY(); - } - - protected BigInteger[] getCommitments(int i){ - return vssHandlers[i -1].getCommitments(); - } - - protected Polynomial.Point getShare(int i){ - return vssHandlers[i-1].getShare(); - } -} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java new file mode 100644 index 0000000..faf0048 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -0,0 +1,288 @@ +package JointFeldmanProtocol; + +import Communication.Network; +import Communication.User; +import ShamirSecretSharing.Polynomial; +import UserInterface.DistributedKeyGenerationUser; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Set; + +/** + * Created by Tzlil on 2/21/2016. + */ +public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { + protected enum ComplainState{ + Non, Waiting,Disqualified,NonDisqualified + } + + protected final DistributedKeyGeneration dkg; + + protected final BigInteger g; + protected final Group group; + protected final int n; + protected final int t; + protected final int id; + + protected MessageHandler messageHandler; + protected final Polynomial.Point[] shares; + protected final BigInteger[][] commitmentsTable; + protected final boolean[] doneFlags; + protected final User user; + protected final ComplainState[][] complaintsTable; + + protected Set QUAL; // set of all non-disqualified parties + protected BigInteger[] commitments; // public verification values + protected Polynomial.Point share; // final share of the secrete + protected BigInteger y; // final public value + + public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network) { + this.dkg = dkg; + + this.g = dkg.getGenerator(); + this.group = dkg.getGroup(); + this.n = dkg.getN(); + this.t = dkg.getT(); + this.id = dkg.getId(); + + this.messageHandler = new MessageHandler(); + this.shares = new Polynomial.Point[n]; + this.shares[id - 1] = dkg.getShare(id); + this.commitmentsTable = new BigInteger[n][t + 1]; + this.doneFlags = new boolean[n]; + this.user = network.connect(messageHandler); + this.complaintsTable = new ComplainState[n][n]; + for (int i = 0; i < n; i++){ + Arrays.fill(complaintsTable[i],ComplainState.Non); + } + + this.QUAL = null; + this.commitments = null; + this.share = null; + this.y = null; + } + + /** + * 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(user); + dkg.sendSecrets(user); + } + + /** + * 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.setShares(shares); + dkg.broadcastComplains(user,commitmentsTable); + //broadcast done message after all complaints + DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + } + + /** + * 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(user,complaintsTable[id - 1]); + + // wait until there is no complaint waiting for answer + for (int i = 0; i < complaintsTable.length; i++){ + for (int j = 0; j < complaintsTable[i].length; j++){ + while (complaintsTable[i][j].equals(ComplainState.Waiting)){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + this.QUAL = dkg.calcQUAL(complaintsTable); + } + + /** + * 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(){ + BigInteger[] ys = new BigInteger[n]; + for (int i = 0; i < n; i++){ + ys[i] = commitmentsTable[i][0]; + } + this.y = dkg.calcY(ys,QUAL); + this.commitments = dkg.calcCommitments(commitmentsTable,QUAL); + this.share = dkg.calcShare(shares,QUAL); + } + + @Override + public void run() { + user.getReceiverThread().start(); + stage1(); + while (messageHandler.secretsCounter != n - 1 || messageHandler.commitmentsCounter != n * (t + 1)){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + stage2(); + while (messageHandler.doneCounter != n){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + stage3(); + stage4(); + user.getReceiverThread().interrupt(); + } + + @Override + public BigInteger[] getCommitments() { + return Arrays.copyOf(commitments, commitments.length); + } + + @Override + public BigInteger getGenerator() { + return g; + } + + @Override + public Group getGroup() { + return group; + } + + @Override + public Polynomial.Point getShare() { + return share; + } + + @Override + public int getID() { + return id; + } + + @Override + public int getN() { + return n; + } + + @Override + public int getT() { + return t; + } + + @Override + public BigInteger getPublicValue() { + return y; + } + + @Override + public Set getQUAL() { + return QUAL; + } + + protected class MessageHandler implements Communication.MessageHandler{ + + public int doneCounter; + public int commitmentsCounter; + public int secretsCounter; + + public MessageHandler() { + this.doneCounter = 0; + this.secretsCounter = 0; + this.commitmentsCounter = 0; + } + + @Override + public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { + if(isBroadcast) { + int i = sender - 1; + int j = complaintMessage.getId() - 1; + switch (complaintsTable[i][j]) { + case Non: + complaintsTable[i][j] = ComplainState.Waiting; + break; + default: + break; + } + } + } + + @Override + public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { + if(isBroadcast && !doneFlags[sender - 1]) { + doneFlags[sender - 1] = true; + doneCounter++; + } + } + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + if(isBroadcast){ + int i = sender - 1; + int k = commitmentMessage.getK(); + if(commitmentsTable[i][k] == null){ + commitmentsTable[i][k] = extractCommitment(commitmentMessage); + commitmentsCounter++; + } + } + } + + @Override + public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { + Polynomial.Point secret = extractSecret(secretMessage); + if(!isBroadcast){ + if(shares[sender - 1] == null) { + shares[sender - 1] = secret; + secretsCounter++; + } + }else { + int i = sender; + int j = secret.x.intValue(); + switch (complaintsTable[i - 1][j - 1]){ + case Waiting: + if(dkg.isValidSecret(secret,commitmentsTable[i - 1],j)){ + complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + }else{ + complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + } + break; + default: + break; + } + } + } + + @Override + public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + + } + + public Polynomial.Point extractSecret(DKGMessages.SecretMessage secretMessage){ + return new Polynomial.Point(secretMessage.getSecret()); + } + + public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ + return new BigInteger(commitmentMessage.getCommitment().toByteArray()); + } + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java index cf0a429..bd204c8 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java @@ -1,10 +1,13 @@ package SecureDistributedKeyGeneration; import Communication.Network; +import Communication.User; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; import JointFeldmanProtocol.DistributedKeyGeneration; +import ShamirSecretSharing.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; @@ -15,54 +18,91 @@ import java.util.Random; */ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { - VerifiableSecretSharing verifiableSecretSharing; + private VerifiableSecretSharing verifiableSecretSharing; + private final BigInteger h; + private Polynomial.Point[] sharesT; - public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger p, BigInteger q, BigInteger g - ,BigInteger h, Network network) { - super(t, n, zi, random, p, q, g, network.connect(new SecureDistributedKeyGenerationMessageHandler(t,n,g,new Zpstar(p)))); - this.verifiableSecretSharing = new VerifiableSecretSharing(t,n,new BigInteger(q.bitLength(), random).mod(q),random,p,q,h,user); + public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g + , BigInteger h, Group group, int id) { + super(t, n, zi, random, q, g, group, id); + this.h = h; + BigInteger r = new BigInteger(q.bitLength(),random).mod(q); + this.verifiableSecretSharing = new VerifiableSecretSharing(t,n,r,random,q,h,group); } @Override - protected void computeAndSendSecrets() { - DKGMessages.SecretMessage[] secretMessages1 = prepareSecretMessages(); - DKGMessages.SecretMessage[] secretMessages2 = verifiableSecretSharing.prepareSecretMessages(); - DKGMessages.DoubleSecretMessage doubleSecretMessage; + public void sendSecret(User user,int j) { + DKGMessages.SecretMessage.Point secret = getShare(j).asMessage();; + DKGMessages.SecretMessage.Point secretT = verifiableSecretSharing.getShare(j).asMessage();; + DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() + .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secret).build()) + .setS2(DKGMessages.SecretMessage.newBuilder().setSecret(secretT).build()) + .build(); + user.send(j, DKGMessages.Mail.Type.DOUBLE, doubleSecretMessage); + } - for (int j = 1; j <= n ; j++ ){ - doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() - .setS1(secretMessages1[j - 1]) - .setS1(secretMessages2[j - 1]) - .build(); - user.send(j, DKGMessages.Mail.Type.SECRET,doubleSecretMessage); + @Override + public boolean isValidSecret(int j, BigInteger[] commitments, int i){ + Polynomial.Point secret = shares[j - 1]; + Polynomial.Point secretT = sharesT[j - 1]; + return isValidSecret(secret,secretT,commitments,i); + } + + public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int i){ + BigInteger v = verify(i,verificationValues,group); + BigInteger exp = group.add(group.multiply(g, secret.y),group.multiply(h, secretT.y)); + return exp.equals(v); + } + + public boolean isValidComplaint(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] commitments + ,BigInteger[] verificationValues, int i){ + return isValidSecret(secret,secretT,verificationValues,i) && !isValidSecret(secret,commitments,i); + } + + /** + * stage4.3 according to the protocol + * if check fails for index i, Pj + */ + public void broadcastComplaints(User user, BigInteger[][] commitmentsTable, boolean stage4){ + if(!stage4){ + broadcastComplains(user,commitmentsTable); + }else{ + for (int j = 1; j <= n ; j++ ){ + if(j != id) { + if (!isValidSecret(shares[j - 1],commitmentsTable[j - 1],id)) { + broadcastDoubleSecret(user,shares[j - 1],sharesT[j - 1]); + } + } + } } } - @Override - public DKGMessages.CommitmentMessage[] prepareCommitmentMessages() { - DKGMessages.CommitmentMessage[] commitmentMessages = new DKGMessages.CommitmentMessage[t + 1]; - BigInteger[] commitments2 = verifiableSecretSharing.getCommitments(); - for (int k = 0; k <= t ; k ++) { - commitmentMessages[k] = DKGMessages.CommitmentMessage.newBuilder() - .setK(k) - .setCommitment(ByteString.copyFrom(zpstar.add(commitments[k],commitments2[k]).toByteArray())) - .build(); + + public void broadcastVerificationValues(User user){ + BigInteger[] verificationValues = new BigInteger[t + 1]; + BigInteger[] hBaseCommitments = verifiableSecretSharing.getCommitmentsArray(); + for (int k = 0 ; k < verificationValues.length ; k++){ + verificationValues[k] = group.add(commitmentsArray[k],hBaseCommitments[k]); } - return commitmentMessages; + broadcastCommitments(user,verificationValues); + } + + private void broadcastDoubleSecret(User user ,Polynomial.Point secret, Polynomial.Point secretT){ + DKGMessages.SecretMessage.Point secretMessage = secret.asMessage(); + DKGMessages.SecretMessage.Point secretTMessage = secretT.asMessage(); + DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() + .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secretMessage).build()) + .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secretTMessage).build()) + .build(); + user.broadcast(DKGMessages.Mail.Type.DOUBLE, doubleSecretMessage); } @Override - protected void answerComplaint(int j) { - DKGMessages.SecretMessage secretMessage1 = DKGMessages.SecretMessage.newBuilder() - .setSecret(getShare(j).asMessage()) - .build(); - DKGMessages.SecretMessage secretMessage2 = DKGMessages.SecretMessage.newBuilder() - .setSecret(verifiableSecretSharing.getShare(j).asMessage()) - .build(); + public void broadcastComplaintAnswer(User user, int j) { + broadcastDoubleSecret(user,getShare(j),verifiableSecretSharing.getShare(j)); + } - user.broadcast(DKGMessages.Mail.Type.SECRET, DKGMessages.DoubleSecretMessage.newBuilder() - .setS1(secretMessage1) - .setS2(secretMessage2) - .build()); + public void setSharesT(Polynomial.Point[] sharesT) { + this.sharesT = sharesT; } } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java deleted file mode 100644 index 034f89c..0000000 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationMessageHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package SecureDistributedKeyGeneration; - -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import JointFeldmanProtocol.DistributedKeyGenerationMessageHandler; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharingMessageHandler; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.concrete.Zpstar; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 2/17/2016. - */ -public class SecureDistributedKeyGenerationMessageHandler extends DistributedKeyGenerationMessageHandler { - - private final SecretSharingMessageHandler[] ssHandlers; - public SecureDistributedKeyGenerationMessageHandler(int t, int n, BigInteger g, Zpstar zpstar) { - super(t, n, g, zpstar); - this.ssHandlers = new SecretSharingMessageHandler[n]; - } - - private boolean isValidSecret(Polynomial.Point secret1,Polynomial.Point secret2,int i){ - int j = secret1.x.intValue(); - BigInteger[] commitments = vssHandlers[i - 1].getCommitments(); - return zpstar.multiply(g,zpstar.add(secret1.y,secret2.y)).equals(VerifiableSecretSharing.verify(j,commitments,zpstar)); - } - - @Override - protected boolean isValidSecret(int i) { - return isValidSecret(getShare(i),ssHandlers[i - 1].getShare(),i); - } - - - @Override - public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - if(!isBroadcast){ - this.handelSecretMessage(sender,isBroadcast,doubleSecretMessage.getS1()); - ssHandlers[sender - 1].handelSecretMessage(sender,isBroadcast,doubleSecretMessage.getS2()); - }else{ - Polynomial.Point secret1 = SecretSharingMessageHandler.extractSecret(doubleSecretMessage.getS1()); - Polynomial.Point secret2 = SecretSharingMessageHandler.extractSecret(doubleSecretMessage.getS2()); - int i = sender; - int j = secret1.x.intValue(); - switch (complainStates[i - 1][j - 1]){ - case Waiting: - if(isValidSecret(secret1,secret2,i)){ - complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; - }else{ - complainStates[i - 1][j - 1] = ComplainState.Disqualified; - } - break; - default: - break; - } - } - } - - -} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java new file mode 100644 index 0000000..02ae13e --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java @@ -0,0 +1,138 @@ +package SecureDistributedKeyGeneration; + +import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; +import ShamirSecretSharing.Polynomial; +import meerkat.protobuf.DKGMessages; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 2/22/2016. + */ +public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { + + private final SecureDistributedKeyGeneration sdkg; + + private final Polynomial.Point[] sharesT; + private final BigInteger[][] verificationValuesTable; + + public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { + super(sdkg, network); + this.sdkg = sdkg; + this.sharesT = new Polynomial.Point[n]; + this.verificationValuesTable = new BigInteger[n][t + 1]; + this.messageHandler = new MessageHandler(); + this.user.setMessageHandler(this.messageHandler); + } + + /** + * 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.broadcastVerificationValues(user); + sdkg.sendSecrets(user); + } + + /** + * 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.setShares(shares); + sdkg.setSharesT(sharesT); + sdkg.broadcastComplains(user,verificationValuesTable); + //broadcast done message after all complaints + DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + } + + private void ys(){ + sdkg.broadcastCommitments(user); + //wait for receive all commitments from all i in QUAL + for (int i:QUAL) { + for(int k = 0; k <= t; k++) { + while (commitmentsTable[i - 1][k] == null) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + sdkg.broadcastComplaints(user,commitmentsTable,true); + //do something with complaints' answers + + } + + @Override + protected void stage4() { + ys(); + super.stage4(); + } + + private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ + + final int NumberOfCommitmentsInStage1 = n * (t + 1); + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + if(isBroadcast){ + if(commitmentsCounter < NumberOfCommitmentsInStage1){ + int i = sender - 1; + int k = commitmentMessage.getK(); + if(verificationValuesTable[i][k] == null){ + verificationValuesTable[i][k] = extractCommitment(commitmentMessage); + commitmentsCounter++; + } + } else{ + super.handelCommitmentMessage(sender,isBroadcast,commitmentMessage); + } + } + } + + @Override + public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { + //there is no secret message in this protocol + } + + @Override + public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + + Polynomial.Point secret = extractSecret(doubleSecretMessage.getS1()); + Polynomial.Point secretT = extractSecret(doubleSecretMessage.getS2()); + if(!isBroadcast){ + if(shares[sender - 1] == null) { + shares[sender - 1] = secret; + sharesT[sender - 1] = secretT; + secretsCounter++; + } + }else { + if(commitmentsCounter <= NumberOfCommitmentsInStage1) { + int i = sender; + int j = secret.x.intValue(); + switch (complaintsTable[i - 1][j - 1]) { + case Waiting: + if (sdkg.isValidSecret(secret,secretT, verificationValuesTable[j - 1], i)) { + complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + } else { + complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + } + break; + default: + break; + } + }else{ // stage4 + + } + } + } + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index de6b847..7dc0bca 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -12,13 +12,11 @@ import java.util.Random; * Created by Tzlil on 1/27/2016. * an implementation of Shamire's secret sharing scheme */ -public class SecretSharing implements Runnable{ +public class SecretSharing{ protected final int t; protected final int n; protected final BigInteger q; - - protected final User user; // send and receive messages throw network - private final Polynomial polynomial; + protected final Polynomial polynomial; /** * constructor @@ -29,16 +27,11 @@ public class SecretSharing implements Runnable{ * @param x secret, chosen from Zq * @param random use for generate random polynomial */ - public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q, Network network) { - this(t,n,x,random,q,network.connect(new SecretSharingMessageHandler())); - } - - public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q, User user) { + public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q) { this.q = q; this.t = t; this.n = n; this.polynomial = generateRandomPolynomial(x,random); - this.user = user; } /** @@ -73,7 +66,7 @@ public class SecretSharing implements Runnable{ * * @return image of interpolation(shares) at x = 0 */ - public static BigInteger getSecrete(Polynomial.Point[] shares) throws Exception { + public static BigInteger restoreSecrete(Polynomial.Point[] shares) throws Exception { Polynomial polynomial = Polynomial.interpolation(shares); return polynomial.image(BigInteger.ZERO); } @@ -102,31 +95,12 @@ public class SecretSharing implements Runnable{ return q; } - public Polynomial getPolynomial() { + /** + * getter + * @return the polynomial was generated in constructor + */ + public Polynomial getPolynomial() { return polynomial; } - - public DKGMessages.SecretMessage[] prepareSecretMessages(){ - DKGMessages.SecretMessage[] secretMessages = new DKGMessages.SecretMessage[n]; - for (int j = 1; j <= n ; j++ ){ - secretMessages[j - 1] = DKGMessages.SecretMessage.newBuilder() - .setSecret(getShare(j).asMessage()) - .build(); - } - return secretMessages; - } - - protected void computeAndSendSecrets(){ - DKGMessages.SecretMessage[] secretMessages = prepareSecretMessages(); - for (int j = 1; j <= n ; j++ ){ - user.send(j, DKGMessages.Mail.Type.SECRET,secretMessages[j - 1]); - } - } - - @Override - public void run() { - // computes and sends shares - computeAndSendSecrets(); - } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java deleted file mode 100644 index 6230c05..0000000 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharingMessageHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -package ShamirSecretSharing; - -import Communication.MessageHandler; -import Communication.Network; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/16/2016. - */ -public class SecretSharingMessageHandler implements MessageHandler{ - - private Polynomial.Point share; - - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { - // ignore - } - - @Override - public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { - // ignore - } - - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - // ignore - } - - @Override - public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - // ignore - } - - @Override - public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { - if(!isBroadcast) - this.share = extractSecret(secretMessage); - } - - public static Polynomial.Point extractSecret(DKGMessages.SecretMessage secretMessage){ - return new Polynomial.Point(secretMessage.getSecret()); - } - - public Polynomial.Point getShare() { - return share; - } -} diff --git a/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java b/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java new file mode 100644 index 0000000..d8eb5ef --- /dev/null +++ b/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java @@ -0,0 +1,13 @@ +package UserInterface; + +import java.math.BigInteger; +import java.util.Set; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface DistributedKeyGenerationUser extends VerifiableSecretSharingUser { + + BigInteger getPublicValue(); + Set getQUAL(); +} diff --git a/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java new file mode 100644 index 0000000..dc4a6e4 --- /dev/null +++ b/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java @@ -0,0 +1,14 @@ +package UserInterface; + +import ShamirSecretSharing.Polynomial; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface SecretSharingUser extends Runnable { + + Polynomial.Point getShare(); + int getID(); + int getN(); + int getT(); +} diff --git a/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java new file mode 100644 index 0000000..79cd404 --- /dev/null +++ b/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java @@ -0,0 +1,16 @@ +package UserInterface; + +import UserInterface.SecretSharingUser; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface VerifiableSecretSharingUser extends SecretSharingUser { + + BigInteger[] getCommitments(); + BigInteger getGenerator(); + Group getGroup(); +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index f773237..fff8952 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -2,6 +2,7 @@ package FeldmanVerifiableSecretSharing; import Communication.Network; import ShamirSecretSharing.Polynomial; +import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; import org.junit.Test; @@ -32,21 +33,19 @@ public class VerifiableSecretSharingTest { }while (!g.equals(ZERO) && !zpstar.multiply(g,q).equals(ZERO));// sample from QRZp* int t = 8; int n = 20; - Network network; verifiableSecretSharingArray = new VerifiableSecretSharing[tests]; for (int i = 0; i < verifiableSecretSharingArray.length; i++){ - network = new Network(n); verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n - ,new BigInteger(q.bitLength(),random).mod(q),random,p,q,g,network); + ,new BigInteger(q.bitLength(),random).mod(q),random,q,g,zpstar); } } public void oneTest(VerifiableSecretSharing verifiableSecretSharing) throws Exception { int n = verifiableSecretSharing.getN(); - Zpstar zpstar = verifiableSecretSharing.getZpstar(); + Group zpstar = verifiableSecretSharing.getGroup(); BigInteger g = verifiableSecretSharing.getGenerator(); Polynomial.Point[] shares = new Polynomial.Point[n]; - BigInteger[] commitments = verifiableSecretSharing.getCommitments(); + BigInteger[] commitments = verifiableSecretSharing.getCommitmentsArray(); BigInteger[] verifications = new BigInteger[n]; for (int i = 1 ; i <= shares.length; i ++){ shares[i - 1] = verifiableSecretSharing.getShare(i); diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index 9171f3d..4000ec0 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -4,13 +4,13 @@ import Communication.Network; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import UserInterface.DistributedKeyGenerationUser; +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.List; import java.util.Random; /** @@ -19,7 +19,7 @@ import java.util.Random; public class DKGTest { - DistributedKeyGeneration[][] dkgsArrays; + DistributedKeyGenerationUser[][] dkgsArrays; Thread[][] threadsArrays; int tests = 10; BigInteger p = BigInteger.valueOf(2903); @@ -33,9 +33,10 @@ public class DKGTest { int t = 9; int n = 20; BigInteger ZERO = zpstar.zero(); - dkgsArrays = new DistributedKeyGeneration[tests][n]; + dkgsArrays = new DistributedKeyGenerationUserImpl[tests][n]; threadsArrays = new Thread[tests][n]; secrets = new BigInteger[tests]; + DistributedKeyGeneration dkg; for (int test = 0; test < tests; test++) { do { g = zpstar.sample(random); @@ -45,13 +46,14 @@ public class DKGTest { for (int i = 0; i < n; i++) { BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); secrets[test] = secrets[test].add(secret).mod(q); - dkgsArrays[test][i] = new DistributedKeyGeneration(t, n,secret, random, p, q, g, network); + dkg = new DistributedKeyGeneration(t,n,secret,random,q,g,zpstar,i + 1); + dkgsArrays[test][i] = new DistributedKeyGenerationUserImpl(dkg,network); threadsArrays[test][i] = new Thread(dkgsArrays[test][i]); } } } - public void oneTest(Thread[] threads, DistributedKeyGeneration[] dkgs,BigInteger secret) throws Exception { + public void oneTest(Thread[] threads, DistributedKeyGenerationUser[] dkgs,BigInteger secret) throws Exception { for (int i = 0; i < threads.length ; i++){ threads[i].start(); } @@ -61,15 +63,16 @@ public class DKGTest { int t = dkgs[0].getT(); int n = dkgs[0].getN(); - Zpstar zpstar = dkgs[0].getZpstar(); + Group zpstar = dkgs[0].getGroup(); BigInteger g = dkgs[0].getGenerator(); // got the right public value - assert(zpstar.multiply(g,secret).equals(dkgs[0].getY())); + BigInteger publicValue = dkgs[0].getPublicValue(); + assert(zpstar.multiply(g,secret).equals(publicValue)); // assert all players agreed on the same public value for (int i = 0; i < dkgs.length - 1 ; i++){ - assert (dkgs[i].getY().equals(dkgs[i+1].getY())); + assert (dkgs[i].getPublicValue().equals(dkgs[i+1].getPublicValue())); } // assert valid verification values @@ -96,19 +99,13 @@ public class DKGTest { // index = indexes.remove(random.nextInt(indexes.size())); // shares[i] = dkgs[index - 1].getShare(); //} - BigInteger calculatedSecret = SecretSharing.getSecrete(shares).mod(q); - - Polynomial polynomial = Polynomial.ZERO; - for (int i = 0 ; i < dkgs.length ; i++){ - polynomial = polynomial.add(dkgs[i].getPolynomial()); - } - + BigInteger calculatedSecret = SecretSharing.restoreSecrete(shares).mod(q); assert (calculatedSecret.equals(secret)); } @Test - public void secretSharingTest() throws Exception { + public void DKGTest() throws Exception { for (int i = 0 ; i < dkgsArrays.length; i ++){ oneTest(threadsArrays[i],dkgsArrays[i],secrets[i]); } diff --git a/destributed-key-generation/src/test/java/SDKGTest.java b/destributed-key-generation/src/test/java/SDKGTest.java new file mode 100644 index 0000000..09bfc2e --- /dev/null +++ b/destributed-key-generation/src/test/java/SDKGTest.java @@ -0,0 +1,113 @@ +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import SecureDistributedKeyGeneration.SecureDistributedKeyGeneration; +import SecureDistributedKeyGeneration.SecureDistributedKeyGenerationUserImpl; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import UserInterface.DistributedKeyGenerationUser; +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.Random; + +/** + * Created by Tzlil on 2/23/2016. + */ +public class SDKGTest { + + DistributedKeyGenerationUser[][] sdkgsArrays; + Thread[][] threadsArrays; + int tests = 10; + BigInteger p = BigInteger.valueOf(2903); + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + BigInteger[] secrets; + @Before + public void settings(){ + Zpstar zpstar = new Zpstar(p); + Random random = new Random(); + BigInteger g,h; + int t = 9; + int n = 20; + BigInteger ZERO = zpstar.zero(); + sdkgsArrays = new SecureDistributedKeyGenerationUserImpl[tests][n]; + threadsArrays = new Thread[tests][n]; + secrets = new BigInteger[tests]; + SecureDistributedKeyGeneration sdkg; + for (int test = 0; test < tests; test++) { + do { + g = zpstar.sample(random); + } while (!g.equals(ZERO) && !zpstar.multiply(g, q).equals(ZERO));// sample from QRZp* + h = zpstar.multiply(g,BigInteger.valueOf(2)); + secrets[test] = BigInteger.ZERO; + Network network = new Network(n); + for (int i = 0; i < n; i++) { + BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); + secrets[test] = secrets[test].add(secret).mod(q); + sdkg = new SecureDistributedKeyGeneration(t,n,secret,random,q,g,h,zpstar,i + 1); + sdkgsArrays[test][i] = new SecureDistributedKeyGenerationUserImpl(sdkg,network); + threadsArrays[test][i] = new Thread(sdkgsArrays[test][i]); + } + } + } + + public void oneTest(Thread[] threads, DistributedKeyGenerationUser[] dkgs,BigInteger secret) throws Exception { + for (int i = 0; i < threads.length ; i++){ + threads[i].start(); + } + for (int i = 0; i < threads.length ; i++){ + threads[i].join(); + } + int t = dkgs[0].getT(); + int n = dkgs[0].getN(); + + Group zpstar = dkgs[0].getGroup(); + BigInteger g = dkgs[0].getGenerator(); + + // got the right public value + BigInteger publicValue = dkgs[0].getPublicValue(); + assert(zpstar.multiply(g,secret).equals(publicValue)); + + // assert all players agreed on the same public value + for (int i = 0; i < dkgs.length - 1 ; i++){ + assert (dkgs[i].getPublicValue().equals(dkgs[i+1].getPublicValue())); + } + + // assert valid verification values + BigInteger expected,verification; + for (int j = 1; j <= dkgs.length ; j++){ + expected = zpstar.multiply(g, dkgs[j - 1].getShare().y); + verification = VerifiableSecretSharing.verify(j, dkgs[j - 1].getCommitments(),zpstar); + assert (expected.equals(verification)); + } + + + // restore the secret from t + 1 random shares + Polynomial.Point[] shares = new Polynomial.Point[t + 1]; + for (int i = 0 ; i < shares.length; i++){ + shares[i] = dkgs[i].getShare(); + } + //List indexes = new ArrayList(n); + //for (int i = 1 ; i <= n; i ++){ + // indexes.add(i); + //} + //Random random = new Random(); + //int index; + //for (int i = 0 ; i < shares.length ; i++){ + // index = indexes.remove(random.nextInt(indexes.size())); + // shares[i] = dkgs[index - 1].getShare(); + //} + BigInteger calculatedSecret = SecretSharing.restoreSecrete(shares).mod(q); + assert (calculatedSecret.equals(secret)); + + } + + @Test + public void SDKGTest() throws Exception { + for (int i = 0 ; i < sdkgsArrays.length; i ++){ + oneTest(threadsArrays[i],sdkgsArrays[i],secrets[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java index 02b8898..8c73ee0 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java @@ -1,7 +1,6 @@ package ShamirSecretSharing; import Communication.Network; -import Communication.User; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; import org.junit.Before; @@ -26,18 +25,17 @@ public class SecretSharingTest { @Before public void settings(){ BigInteger p = BigInteger.valueOf(2903); + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); group = new Zn(p); int t = 9; int n = 20; random = new Random(); secretSharingArray = new SecretSharing[tests]; secrets = new BigInteger[tests]; - Network network; for (int i = 0; i < secretSharingArray.length; i++){ secrets[i] = group.sample(random); - network = new Network(n); - secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,p,network); + secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,q); } } @@ -52,7 +50,7 @@ public class SecretSharingTest { for (int i = 0 ; i < shares.length ; i++){ shares[i] = secretSharing.getShare(indexes.remove(random.nextInt(indexes.size()))); } - assert(secret.equals(SecretSharing.getSecrete(shares))); + assert(secret.equals(SecretSharing.restoreSecrete(shares))); } @Test diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto index c01b004..4fbc4da 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -10,6 +10,7 @@ message Mail{ COMMITMENT = 1; DONE = 2; COMPLAINT = 3; + DOUBLE = 4; } int32 sender = 1; int32 destination = 2; From 77f47fe9e1620c1296168feb5fd46738ae0d3774 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 23 Feb 2016 16:58:35 +0200 Subject: [PATCH 022/106] First version of Voter Booth Summary: Planned some basic interfaces for my revised Voting Booth componenets. No implementation yet, though... Test Plan: There are none, yet Reviewers: arbel.peled Differential Revision: https://proj-cs.idc.ac.il/D2 --- .../src/main/proto/meerkat/voting.proto | 37 +++++++-- .../meerkat/voting/BallotOutputDevice.java | 19 +++++ .../main/java/meerkat/voting/Encryptor.java | 13 +++ .../java/meerkat/voting/StorageManager.java | 12 +++ .../voting/SystemConsoleOutputDevice.java | 56 +++++++++++++ .../src/main/java/meerkat/voting/UI.java | 32 ++++++++ .../main/java/meerkat/voting/VotingBooth.java | 82 +++++++++++++++++++ 7 files changed, 245 insertions(+), 6 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/Encryptor.java create mode 100644 voting-booth/src/main/java/meerkat/voting/StorageManager.java create mode 100644 voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/UI.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBooth.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 9837cce..759a708 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -6,13 +6,38 @@ 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; + + +// Type of the element data to be presented by UI +enum UIElementDataType { + TEXT = 0; + IMAGE = 1; + VOICE = 2; } +// Type of question +enum QuestionType { + MULTIPLE_CHOICE = 0; + MULTIPLE_SELECTION = 1; + ORDER = 2; +} + +// An element to be presented by UI +message UIElement { + UIElementDataType type = 1; + bytes data = 2; +} + +// a new data structure for BallotQuestion. Need to delete the old one +message BallotQuestion { + bool is_mandatory = 1; + UIElement question = 2; + UIElement description = 3; + repeated UIElement answer = 4; +} + + + // An answer to a specific ballot question. // The answer is a vector of signed integers, // to encompass voting schemes such as ranked voting @@ -83,7 +108,7 @@ message ElectionParams { repeated BallotQuestion questions = 6; // Translation table between answers and plaintext encoding - BallotAnswerTranslationTable answerTranslationTable = 7; + //BallotAnswerTranslationTable answerTranslationTable = 7; // Data required in order to access the Bulletin Board Servers BulletinBoardClientParams bulletinBoardClientParams = 8; diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java new file mode 100644 index 0000000..32e3208 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -0,0 +1,19 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 15/02/16. + */ +public interface BallotOutputDevice { + + void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback); + + void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback); + + void castBallot(long sessionId, VotingBooth.Callback callback); + + // probably has no difference than cast. Maybe drop this method + void cancelBallot(long sessionId, VotingBooth.Callback callback); + +} diff --git a/voting-booth/src/main/java/meerkat/voting/Encryptor.java b/voting-booth/src/main/java/meerkat/voting/Encryptor.java new file mode 100644 index 0000000..4cfcf57 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/Encryptor.java @@ -0,0 +1,13 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface Encryptor { + + public void encrypt (long sessionId, PlaintextBallot plaintextBallot); + + //TODO: probably needs some key generation methods as well +} diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java new file mode 100644 index 0000000..3edff7a --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -0,0 +1,12 @@ +package meerkat.voting; + +/** + * Created by hai on 23/02/16. + */ +public interface StorageManager { + + // should these methods be synchronous or asynchronous? Can we rely on it being immediate? + public void detectAdminHardwareKey(); + + public void readElectionParams (); +} diff --git a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java new file mode 100644 index 0000000..7546d53 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java @@ -0,0 +1,56 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 15/02/16. + */ +public class SystemConsoleOutputDevice implements BallotOutputDevice { + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + + @Override + public void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback) { + + System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " + + bytesToString(encryptedBallot.getData().getData())); + + callback.ballotCommitResult(sessionId, true); + + } + + @Override + public void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback) { + + //TODO: generate standard form for this + System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " + + bytesToString(encryptedBallot.getData().getData())); + + callback.ballotAuditResult(sessionId, true); + + } + + @Override + public void castBallot(long sessionId, VotingBooth.Callback callback) { + + System.out.println("Ballot finalized!"); + + callback.ballotCastResult(sessionId, true); + + } + + @Override + public void cancelBallot(long sessionId, VotingBooth.Callback callback) { + + System.out.println("Ballot cancelled!"); + + callback.ballotCancelResult(sessionId, true); + + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/UI.java b/voting-booth/src/main/java/meerkat/voting/UI.java new file mode 100644 index 0000000..83739db --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/UI.java @@ -0,0 +1,32 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface UI { + + + // Voter scenario methods + void introductionToVoter (long sessionId); + + void chooseChannel (long sessionId, BallotQuestion question); + + void askVoterQuestion (long sessionId, int questionNumber, BallotQuestion question); + + void castOrAudit (long sessionId); + + void showWaitForFinishScreen (long sessionId); + + + // Admin scenario methods + //TODO: the admin scenario still needs some more thinking + + + + // bad thing happened scenario + void showErrorMessageAndHalt (String errorMessage); + void showErrorMessageWithCancelButton (long sessionId, String errorMessage); + +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java new file mode 100644 index 0000000..a7df483 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -0,0 +1,82 @@ +package meerkat.voting; + +import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface VotingBooth { + + public enum ErrorID { + OUTPUT_DEVICE_OUT_OF_PAPER, + OUTPUT_DEVICE_OUT_OF_INK, + OUTPUT_DEVICE_NO_CONNECTION, + OUTPUT_DEVICE_HARDWARE_NOT_FOUND, + + UI_HARDWARE_NOT_FOUND + } + + + // keeps track in which state we are + // internal state will also include the number of the current question and the answers we got so far, + // later it includes the details of the PlaintextBallot and later the Encryption and the secrets + public enum State { + INITIALIZED, + + VOTER_INTRODUCTION, + VOTER_CHOOSE_CHANNEL, + VOTER_VOTING, + VOTER_ENCRYPTING, + VOTER_CAST_OR_AUDIT, + VOTER_CASTING, + VOTER_AUDITING + + } + + public interface Callback { + + // callbacks and messages from BallotOutputDevice + + public void ballotCommitResult (long sessionId, boolean result); + public void ballotCastResult (long sessionId, boolean result); + public void ballotAuditResult (long sessionId, boolean result); + public void ballotCancelResult (long sessionId, boolean result); + // other error messages, such as Printer turned-off or out-of-paper + public void outputDeviceReportProblem (ErrorID errorId); + + + // callbacks and messages from UI + + public void introductionFinished (long sessionId); + public void choiceOfChannel (long sessionId, int channelNumber); + public void skipQuestion (long sessionId, int questionNumber); + public void backwardsQuestion (long sessionId, int questionNumber); + public void cancelVotingSession (long sessionId); + public void answer (long sessionId, int questionNumber, String answer); + public void cast (long sessionId); + public void audit (long sessionId); + // other error messages, such as hardware-not-detected + public void uiReportProblem (ErrorID errorId); + + + // callbacks from encryptor + + public void returnEncryption (long sessionId, EncryptedBallot encryptedBallot, BallotSecrets secrets); + + + // callbacks from StorageManager + + public void adminHardwareKeyDetected (boolean isKeyInserted); + public void loadElectionParams (ElectionParams electionParams); + } + + // this function is synchronous + public void start (); + + + // messages from Admin Console (If there is such one) + // this function is asynchronous + public void shutDown(); + +} From 71191e05b9ab8c807d6fcad8487757f5fbd43aca Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 29 Feb 2016 08:36:35 +0200 Subject: [PATCH 023/106] Added Sync Query tests on Bulletin Board Server --- .../sqlserver/SQLiteQueryProvider.java | 92 +++++++++++++++++++ .../GenericBulletinBoardServerTest.java | 88 +++++++++++++++++- .../MySQLBulletinBoardServerTest.java | 13 +++ .../java/meerkat/comm/MessageInputStream.java | 30 +++++- .../java/meerkat/util/BulletinBoardUtils.java | 2 +- 5 files changed, 219 insertions(+), 6 deletions(-) diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index b581b87..b64412d 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -4,6 +4,7 @@ import meerkat.protobuf.BulletinBoardAPI.*; import org.sqlite.SQLiteDataSource; import javax.sql.DataSource; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; @@ -25,19 +26,97 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi 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); } @@ -52,21 +131,34 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi 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); } diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index e33c739..1e7921d 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -24,9 +24,12 @@ import meerkat.comm.CommunicationException; import meerkat.comm.MessageInputStream; import meerkat.comm.MessageOutputStream; import meerkat.comm.MessageInputStream.MessageInputStreamFactory; +import meerkat.crypto.Digest; import meerkat.crypto.concrete.ECDSASignature; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.util.BulletinBoardUtils; +import meerkat.util.BulletinBoardMessageGenerator; +import org.h2.util.DateTimeUtils; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; @@ -59,6 +62,10 @@ public class GenericBulletinBoardServerTest { private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests + private BulletinBoardMessageGenerator bulletinBoardMessageGenerator; + + private Digest digest; + /** * @param bulletinBoardServer is an initialized server. * @throws InstantiationException @@ -121,8 +128,12 @@ public class GenericBulletinBoardServerTest { System.err.println("Couldn't find signing key " + e.getMessage()); fail("Couldn't find signing key " + e.getMessage()); } - - random = new Random(0); // We use insecure randomness in tests for repeatability + + // We use insecure randomness in tests for repeatability + random = new Random(0); + bulletinBoardMessageGenerator = new BulletinBoardMessageGenerator(random); + + digest = new SHA256Digest(); long end = threadBean.getCurrentThreadCpuTime(); System.err.println("Finished initializing GenericBulletinBoardServerTest"); @@ -182,7 +193,10 @@ public class GenericBulletinBoardServerTest { for (i = 1; i <= MESSAGE_NUM; i++) { unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder() .setData(ByteString.copyFrom(data[i - 1])) - .setTimestamp(BulletinBoardUtils.toTimestampProto()); + .setTimestamp(Timestamp.newBuilder() + .setSeconds(i) + .setNanos(i) + .build()); // Add tags based on bit-representation of message number. @@ -619,6 +633,72 @@ public class GenericBulletinBoardServerTest { } } + + public void testSyncQuery() + throws SignatureException, CommunicationException, IOException,NoSuchMethodException, IllegalAccessException, InvocationTargetException { + + Timestamp timestamp = Timestamp.newBuilder() + .setSeconds(1) + .setNanos(0) + .build(); + + BulletinBoardMessage newMessage = bulletinBoardMessageGenerator.generateRandomMessage(signers, timestamp, 10, 10); + + BoolMsg result = bulletinBoardServer.postMessage(newMessage); + assertThat("Failed to post message to BB Server", result.getValue(), is(true)); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + digest.update(newMessage.getMsg()); + + ByteString messageID = ByteString.copyFrom(digest.digest()); + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(messageID) + .build()) + .build(); + + bulletinBoardServer.readMessages(filterList, new MessageOutputStream(outputStream)); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream(new ByteArrayInputStream( + outputStream.toByteArray()), + BulletinBoardMessage.class); + + long lastEntry = inputStream.asList().get(0).getEntryNum(); + + SyncQuery syncQuery = SyncQuery.newBuilder() + .setFilterList(MessageFilterList.getDefaultInstance()) + .addQuery(SingleSyncQuery.newBuilder() + .setChecksum(2) + .setTimeOfSync(Timestamp.newBuilder() + .setSeconds(2) + .setNanos(0) + .build()) + .build()) + .build(); + + SyncQueryResponse queryResponse = bulletinBoardServer.querySync(syncQuery); + + assertThat("Sync query replies with positive sync when no sync was expected", queryResponse.getLastEntryNum(), is(equalTo(-1l))); + + syncQuery = SyncQuery.newBuilder() + .setFilterList(MessageFilterList.getDefaultInstance()) + .addQuery(SingleSyncQuery.newBuilder() + .setChecksum(messageID.byteAt(0) & messageID.byteAt(1) & messageID.byteAt(2) & messageID.byteAt(3)) + .setTimeOfSync(timestamp) + .build()) + .build(); + + queryResponse = bulletinBoardServer.querySync(syncQuery); + + assertThat("Sync query reply contained wrong last entry number", lastEntry, is(equalTo(queryResponse.getLastEntryNum()))); + + assertThat("Sync query reply contained wrong timestamp", timestamp, is(equalTo(queryResponse.getLastTimeOfSync()))); + + } public void close(){ signers[0].clearSigningKey(); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java index 42c11f7..273a53f 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -8,8 +8,11 @@ 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; @@ -144,6 +147,16 @@ public class MySQLBulletinBoardServerTest { } + @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"); diff --git a/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java index 33deb3f..dc637d9 100644 --- a/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java +++ b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java @@ -5,6 +5,7 @@ import com.google.protobuf.Message; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -12,7 +13,7 @@ import java.util.List; * Created by Arbel Deutsch Peled on 21-Feb-16. * A input stream of Protobuf messages */ -public class MessageInputStream{ +public class MessageInputStream implements Iterable{ private T.Builder builder; @@ -23,6 +24,33 @@ public class MessageInputStream{ this.builder = (T.Builder) type.getMethod("newBuilder").invoke(type); } + @Override + public Iterator iterator() { + + return new Iterator() { + + @Override + public boolean hasNext() { + try { + return isAvailable(); + } catch (IOException e) { + return false; + } + } + + @Override + public T next() { + try { + return readMessage(); + } catch (IOException e) { + return null; + } + } + + }; + + } + /** * Factory class for actually creating a MessageInputStream */ diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java index d8b362c..8793b2d 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.java @@ -80,7 +80,7 @@ public class BulletinBoardUtils { * This method creates a Timestamp Protobuf from the current system time * @return a Timestamp Protobuf encoding of the current system time */ - public static com.google.protobuf.Timestamp toTimestampProto() { + public static com.google.protobuf.Timestamp getCurrentTimestampProto() { return toTimestampProto(System.currentTimeMillis()); From 1cf14a60a805a17ebcc795d64a990317c4b414a3 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Tue, 1 Mar 2016 13:56:18 +0200 Subject: [PATCH 024/106] Bulletin Board Client support for streaming and Timestamps Created standard Checksum interface and implementation for Sync Query mechanism Added the Timestamp into the Batch Digest and Signature logic --- .../SingleServerBulletinBoardClient.java | 6 +- .../SingleServerReadBatchWorker.java | 30 ++-- .../SingleServerReadMessagesWorker.java | 32 +++-- ...dedBulletinBoardClientIntegrationTest.java | 20 ++- .../sqlserver/BulletinBoardSQLServer.java | 20 +-- .../GenericBulletinBoardServerTest.java | 4 +- .../java/meerkat/bulletinboard/Checksum.java | 122 ++++++++++++++++ .../bulletinboard/GenericBatchDigest.java | 2 + .../GenericBatchDigitalSignature.java | 3 + .../meerkat/bulletinboard/SimpleChecksum.java | 131 ++++++++++++++++++ .../java/meerkat/comm/MessageInputStream.java | 6 + .../meerkat/comm/MessageOutputStream.java | 4 + 12 files changed, 342 insertions(+), 38 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/Checksum.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/SimpleChecksum.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index ea0e93d..24cd6bf 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -381,11 +381,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void onSuccess(Boolean msg) { closeBatch( - CloseBatchMessage.newBuilder() - .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) - .setSig(completeBatch.getSignature()) - .setBatchLength(completeBatch.getBatchDataList().size()) - .build(), + completeBatch.getCloseBatchMessage(), callback ); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java index 11fc777..57b336e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java @@ -3,6 +3,7 @@ package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.CompleteBatch; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageInputStream; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; @@ -12,6 +13,9 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.util.List; import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; @@ -40,29 +44,33 @@ public class SingleServerReadBatchWorker extends SingleServerWorker inputStream = null; try { - // If a BatchDataList is returned: the read was successful - return response.readEntity(BatchDataList.class).getDataList(); + inputStream = MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BatchData.class); - } catch (ProcessingException | IllegalStateException e) { + return inputStream.asList(); + + } catch (IOException | InvocationTargetException e) { // Read failed - throw new CommunicationException("Could not contact the server"); + throw new CommunicationException("Could not contact the server or server returned illegal result"); - } - finally { - response.close(); + } catch (NoSuchMethodException | IllegalAccessException e) { + + throw new CommunicationException("MessageInputStream error"); + + } finally { + try { + inputStream.close(); + } catch (IOException ignored) {} } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java index 6c09bcc..d8525ab 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadMessagesWorker.java @@ -2,6 +2,8 @@ package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageInputStream; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; @@ -13,6 +15,9 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.util.List; import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; @@ -38,30 +43,33 @@ public class SingleServerReadMessagesWorker extends SingleServerWorker inputStream = null; try { - // If a BulletinBoardMessageList is returned: the read was successful - return response.readEntity(BulletinBoardMessageList.class).getMessageList(); + inputStream = MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BulletinBoardMessage.class); - } catch (ProcessingException | IllegalStateException e) { + return inputStream.asList(); + + } catch (IOException | InvocationTargetException e) { // Read failed - throw new CommunicationException("Could not contact the server"); + throw new CommunicationException("Could not contact the server or server returned illegal result"); - } - finally { - response.close(); - } + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new CommunicationException("MessageInputStream error"); + + } finally { + try { + inputStream.close(); + } catch (IOException ignored) {} + } } diff --git a/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java index dfccebc..59aa615 100644 --- a/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java @@ -1,5 +1,6 @@ import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.ByteString; +import com.google.protobuf.*; +import com.google.protobuf.Timestamp; import meerkat.bulletinboard.AsyncBulletinBoardClient; import meerkat.bulletinboard.CompleteBatch; import meerkat.bulletinboard.GenericBatchDigitalSignature; @@ -284,6 +285,11 @@ public class ThreadedBulletinBoardClientIntegrationTest { } + completeBatch.setTimestamp(Timestamp.newBuilder() + .setSeconds(Math.abs(90)) + .setNanos(50) + .build()); + signers[signer].updateContent(completeBatch); completeBatch.setSignature(signers[signer].sign()); @@ -357,6 +363,10 @@ public class ThreadedBulletinBoardClientIntegrationTest { .addTag("Signature") .addTag("Trustee") .setData(ByteString.copyFrom(b1)) + .setTimestamp(Timestamp.newBuilder() + .setSeconds(20) + .setNanos(30) + .build()) .build()) .addSig(Crypto.Signature.newBuilder() .setType(Crypto.SignatureType.DSA) @@ -440,6 +450,10 @@ public class ThreadedBulletinBoardClientIntegrationTest { CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() .setBatchId(BATCH_ID) .setBatchLength(BATCH_LENGTH) + .setTimestamp(Timestamp.newBuilder() + .setSeconds(50) + .setNanos(80) + .build()) .setSig(completeBatch.getSignature()) .build(); @@ -525,6 +539,10 @@ public class ThreadedBulletinBoardClientIntegrationTest { .setBatchId(NON_EXISTENT_BATCH_ID) .setBatchLength(1) .setSig(Crypto.Signature.getDefaultInstance()) + .setTimestamp(Timestamp.newBuilder() + .setSeconds(9) + .setNanos(12) + .build()) .build(); // Try to close the (unopened) batch; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index b4e2949..c7bcf57 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -446,9 +446,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID); Map namedParameters = new HashMap(); + namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID); - List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new LongMapper()); + List entryNums = jdbcTemplate.query(sql, namedParameters, new LongMapper()); if (entryNums.size() > 0){ @@ -462,7 +463,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ namedParameters.put(QueryType.INSERT_MSG.getParamName(2), msg.getMsg().toByteArray()); KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); + jdbcTemplate.update(sql, new MapSqlParameterSource(namedParameters), keyHolder); entryNum = keyHolder.getKey().longValue(); @@ -785,6 +786,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ .build() ); + // Add timestamp to CompleteBatch + completeBatch.setTimestamp(message.getTimestamp()); + // Add actual batch data to CompleteBatch sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); @@ -903,20 +907,20 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ long lastEntryNum = getLastMessageEntry(); - long checksum = 0; - Iterator queryIterator = syncQuery.getQueryList().iterator(); SingleSyncQuery currentQuery = queryIterator.next(); List messageStubs = readMessageStubs(syncQuery.getFilterList()); + Checksum checksum = new SimpleChecksum(); + for (BulletinBoardMessage message : messageStubs){ // Check for end of current query if (timestampComparator.compare(message.getMsg().getTimestamp(), currentQuery.getTimeOfSync()) > 0){ - if (checksum == currentQuery.getChecksum()){ + if (checksum.getChecksum() == currentQuery.getChecksum()){ lastTimeOfSync = currentQuery.getTimeOfSync(); } else { break; @@ -932,13 +936,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Advance checksum - ByteString messageID = message.getMsg().getData(); + ByteString messageID = message.getMsg().getData(); // The data field contains the message ID - checksum &= messageID.byteAt(0) & messageID.byteAt(1) & messageID.byteAt(2) & messageID.byteAt(3); + checksum.update(messageID); } - if (checksum == currentQuery.getChecksum()){ + if (checksum.getChecksum() == currentQuery.getChecksum()){ lastTimeOfSync = currentQuery.getTimeOfSync(); } diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 1e7921d..affb1a3 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -637,6 +637,8 @@ public class GenericBulletinBoardServerTest { public void testSyncQuery() throws SignatureException, CommunicationException, IOException,NoSuchMethodException, IllegalAccessException, InvocationTargetException { + Checksum checksum = new SimpleChecksum(); + Timestamp timestamp = Timestamp.newBuilder() .setSeconds(1) .setNanos(0) @@ -687,7 +689,7 @@ public class GenericBulletinBoardServerTest { syncQuery = SyncQuery.newBuilder() .setFilterList(MessageFilterList.getDefaultInstance()) .addQuery(SingleSyncQuery.newBuilder() - .setChecksum(messageID.byteAt(0) & messageID.byteAt(1) & messageID.byteAt(2) & messageID.byteAt(3)) + .setChecksum(checksum.getChecksum(messageID)) .setTimeOfSync(timestamp) .build()) .build(); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/Checksum.java b/meerkat-common/src/main/java/meerkat/bulletinboard/Checksum.java new file mode 100644 index 0000000..b8ddb0b --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/Checksum.java @@ -0,0 +1,122 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.ByteString; +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.MessageID; + +import java.util.Collection; + +/** + * Created by Arbel Deutsch Peled on 01-Mar-16. + * This interface is used to create checksums of Bulletin Board messages IDs + * This is useful in comparing database states + */ +public interface Checksum { + + /** + * Sets the Digest method which is used in creating message IDs from the messages themselves + * This method must be called with an initialized Digest before calling any methods that receive a parameter of type BulletinBoardMessage + * @param digest is the Digest that will be used to create message IDs from Bulletin Board Messages + */ + public void setDigest(Digest digest); + + /** + * Used to reset the current checksum state + */ + public void reset(); + + /** + * Update the current checksum with the given ID + * @param messageID is the message ID to be added + */ + public void update(MessageID messageID); + + /** + * Update the current checksum with the given collection of IDs + * @param messageIDs contains the message IDs + */ + public void update(Collection messageIDs); + + /** + * Update the current checksum with the given ID + * @param messageID is the message ID to be added + */ + public void update(ByteString messageID); + + /** + * Update the current checksum with the given ID + * @param messageID is the message ID to be added + */ + public void update(byte[] messageID); + + /** + * Update the current checksum with the message ID of the given message + * @param bulletinBoardMessage is the message whose ID should be added to the checksum + * @throws IllegalStateException if a Digest has not been set before calling this method + */ + public void digestAndUpdate(BulletinBoardMessage bulletinBoardMessage) throws IllegalStateException; + + + /** + * Update the current checksum with the message IDs of the given messages + * @param bulletinBoardMessages contains the messages whose IDs should be added to the checksum + * @throws IllegalStateException if a Digest has not been set before calling this method + */ + public void digestAndUpdate(Collection bulletinBoardMessages) throws IllegalStateException; + + /** + * Returns the current checksum without changing the checksum state + * @return the current checksum + */ + public long getChecksum(); + + /** + * Updates the current checksum with the given ID and returns the resulting checksum + * The checksum is not reset afterwards + * @param messageID is the message ID to be added + * @return the updated checksum + */ + public long getChecksum(MessageID messageID); + + /** + * Updates the current checksum with the given ID and returns the resulting checksum + * The checksum is not reset afterwards + * @param messageID is the message ID to be added + * @return the updated checksum + */ + public long getChecksum(ByteString messageID); + + /** + * Updates the current checksum with the given ID and returns the resulting checksum + * The checksum is not reset afterwards + * @param messageID is the message ID to be added + * @return the updated checksum + */ + public long getChecksum(byte[] messageID); + + /** + * Updates the current checksum with the given IDs and returns the resulting checksum + * The checksum is not reset afterwards + * @param messageIDs contains the message IDs to be added + * @return the updated checksum + */ + public long getChecksum(Collection messageIDs); + + /** + * Updates the current checksum with the message ID of the given message + * The checksum is not reset afterwards + * @param bulletinBoardMessage is the message whose ID should be added to the checksum + * @return the updated checksum + */ + public long digestAndGetChecksum(BulletinBoardMessage bulletinBoardMessage) throws IllegalStateException; + + /** + * Updates the current checksum with the message IDs of the given messages + * The checksum is not reset afterwards + * @param bulletinBoardMessages contains the messages whose IDs should be added to the checksum + * @return the updated checksum + */ + public long digestAndGetChecksum(Collection bulletinBoardMessages) throws IllegalStateException; + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java index 4f25f59..852bb24 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java @@ -29,6 +29,8 @@ public class GenericBatchDigest implements BatchDigest{ update(batchData); } + update(completeBatch.getTimestamp()); + } @Override diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java index 7174b42..7327b8e 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigitalSignature.java @@ -32,10 +32,13 @@ public class GenericBatchDigitalSignature implements BatchDigitalSignature{ public void updateContent(CompleteBatch completeBatch) throws SignatureException { digitalSignature.updateContent(completeBatch.getBeginBatchMessage()); + for (BatchData batchData : completeBatch.getBatchDataList()) { digitalSignature.updateContent(batchData); } + digitalSignature.updateContent(completeBatch.getTimestamp()); + } @Override diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SimpleChecksum.java b/meerkat-common/src/main/java/meerkat/bulletinboard/SimpleChecksum.java new file mode 100644 index 0000000..90d7ae5 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/SimpleChecksum.java @@ -0,0 +1,131 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.ByteString; +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.MessageID; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; + +import java.util.Collection; + +/** + * Created by Arbel Deutsch Peled on 01-Mar-16. + * Implementation of Checksum via bitwise XOR of the bytes of message IDs + */ +public class SimpleChecksum implements Checksum{ + + private Digest digest; + private long checksum; + + public SimpleChecksum() { + digest = null; + reset(); + } + + @Override + public void setDigest(Digest digest) { + this.digest = digest; + } + + @Override + public void reset() { + checksum = 0; + } + + @Override + public void update(MessageID messageID) { + ByteString messageIDByteString = messageID.getID(); + update(messageIDByteString); + } + + @Override + public void update(Collection messageIDs) { + + for (MessageID messageID : messageIDs){ + update(messageID); + } + + } + + @Override + public void update(ByteString messageID) { + for (int i = 0 ; i < messageID.size() ; i++){ + checksum &= messageID.byteAt(i); + } + } + + @Override + public void update(byte[] messageID) { + for (int i = 0 ; i < messageID.length ; i++){ + checksum &= messageID[i]; + } + } + + private void checkDigest() throws IllegalStateException { + + if (digest == null){ + throw new IllegalStateException("Digest method not set. Use setDigest method before calling digestAndUpdate."); + } + + } + + @Override + public void digestAndUpdate(BulletinBoardMessage bulletinBoardMessage) throws IllegalStateException { + + checkDigest(); + + digest.reset(); + digest.update(bulletinBoardMessage); + update(digest.digest()); + + } + + @Override + public void digestAndUpdate(Collection bulletinBoardMessages) throws IllegalStateException { + + for (BulletinBoardMessage bulletinBoardMessage : bulletinBoardMessages){ + digestAndUpdate(bulletinBoardMessage); + } + + } + + @Override + public long getChecksum() { + return checksum; + } + + @Override + public long getChecksum(MessageID messageID) { + update(messageID); + return getChecksum(); + } + + @Override + public long getChecksum(ByteString messageID) { + update(messageID); + return getChecksum(); + } + + @Override + public long getChecksum(byte[] messageID) { + update(messageID); + return getChecksum(); + } + + @Override + public long getChecksum(Collection messageIDs) { + update(messageIDs); + return getChecksum(); + } + + @Override + public long digestAndGetChecksum(BulletinBoardMessage bulletinBoardMessage) throws IllegalStateException { + digestAndUpdate(bulletinBoardMessage); + return getChecksum(); + } + + @Override + public long digestAndGetChecksum(Collection bulletinBoardMessages) throws IllegalStateException { + digestAndUpdate(bulletinBoardMessages); + return getChecksum(); + } +} diff --git a/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java index dc637d9..b1e5255 100644 --- a/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java +++ b/meerkat-common/src/main/java/meerkat/comm/MessageInputStream.java @@ -89,4 +89,10 @@ public class MessageInputStream implements Iterable{ } + public void close() throws IOException { + + in.close(); + + } + } diff --git a/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java b/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java index b55bc8e..f72c04c 100644 --- a/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java +++ b/meerkat-common/src/main/java/meerkat/comm/MessageOutputStream.java @@ -21,4 +21,8 @@ public class MessageOutputStream { message.writeDelimitedTo(out); } + public void close() throws IOException { + out.close(); + } + } From cc7e138a4303b7df7cee4a244f78e669d92e265e Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 1 Mar 2016 16:49:55 +0200 Subject: [PATCH 025/106] redesigned mail handler --- .../main/java/Communication/MailHandler.java | 43 +-- .../java/Communication/MessageHandler.java | 12 +- .../src/main/java/Communication/Network.java | 4 +- .../src/main/java/Communication/User.java | 10 +- .../VerifiableSecretSharing.java | 2 +- .../DistributedKeyGeneration.java | 39 +-- .../DistributedKeyGenerationMailHandler.java | 46 ++++ .../DistributedKeyGenerationUserImpl.java | 130 +++++---- ...ecureDistributedKeyGenerationUserImpl.java | 138 ---------- .../SecureDistributedKeyGeneration.java | 63 ++--- ...reDistributedKeyGenerationMailHandler.java | 60 +++++ ...ecureDistributedKeyGenerationUserImpl.java | 247 ++++++++++++++++++ .../java/ShamirSecretSharing/Polynomial.java | 17 -- .../ShamirSecretSharing/SecretSharing.java | 2 +- .../java/JointFeldmanProtocol/DKGTest.java | 2 +- .../src/test/java/SDKGTest.java | 6 +- .../SecretSharingTest.java | 3 +- .../src/main/proto/meerkat/DKGMessages.proto | 25 +- 18 files changed, 546 insertions(+), 303 deletions(-) create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java delete mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java rename destributed-key-generation/src/main/java/{SecureDistributedKeyGeneration => SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem}/SecureDistributedKeyGeneration.java (53%) create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/Communication/MailHandler.java index 618ba4f..13bd347 100644 --- a/destributed-key-generation/src/main/java/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MailHandler.java @@ -1,50 +1,53 @@ package Communication; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/14/2016. */ -public class MailHandler { +public abstract class MailHandler { private MessageHandler messageHandler; public MailHandler(MessageHandler messageHandler){ this.messageHandler = messageHandler; } + public abstract Message extractMessage(DKGMessages.Mail mail); - public void handel(DKGMessages.Mail mail) throws InvalidProtocolBufferException { - switch (mail.getType()){ + public void handel(DKGMessages.Mail mail){ + + Message message = extractMessage(mail); + if (message == null) + return; + + switch (mail.getType()) { case SECRET: - DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); - messageHandler.handelSecretMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,secretMessage); + messageHandler.handelSecretMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); break; case COMMITMENT: - DKGMessages.CommitmentMessage commitmentMessage = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - messageHandler.handelCommitmentMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,commitmentMessage); + messageHandler.handelCommitmentMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); break; case DONE: - DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); - messageHandler.handelDoneMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,doneMessage); + messageHandler.handelDoneMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); break; case COMPLAINT: - DKGMessages.ComplaintMessage complaintMessage = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); - messageHandler.handelComplaintMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,complaintMessage); + messageHandler.handelComplaintMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); break; - case DOUBLE: - DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - messageHandler.handelDoubleSecretMessage(mail.getSender(),mail.getDestination()== Network.BROADCAST,doubleSecretMessage); + case ANSWER: + messageHandler.handelAnswerMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); default: break; } + + } - - - public MessageHandler getMessageHandler(){ - return messageHandler; - } - public void setMessageHandler(MessageHandler messageHandler) { this.messageHandler = messageHandler; } diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/Communication/MessageHandler.java index 8d1447e..a12a600 100644 --- a/destributed-key-generation/src/main/java/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MessageHandler.java @@ -1,14 +1,14 @@ package Communication; -import meerkat.protobuf.DKGMessages; +import com.google.protobuf.Message; /** * Created by Tzlil on 2/14/2016. */ public interface MessageHandler { - void handelComplaintMessage(int sender, boolean isBroadcast,DKGMessages.ComplaintMessage complaintMessage); - void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage); - void handelCommitmentMessage(int sender, boolean isBroadcast,DKGMessages.CommitmentMessage commitmentMessage); - void handelSecretMessage(int sender, boolean isBroadcast,DKGMessages.SecretMessage secretMessage); - void handelDoubleSecretMessage(int sender, boolean isBroadcast,DKGMessages.DoubleSecretMessage doubleSecretMessage); + void handelSecretMessage(int sender, boolean isBroadcast, Message message); + void handelCommitmentMessage(int sender, boolean isBroadcast, Message message); + void handelComplaintMessage(int sender, boolean isBroadcast, Message message); + void handelDoneMessage(int sender, boolean isBroadcast, Message message); //will be remove + void handelAnswerMessage(int sender, boolean isBroadcast, Message message); } diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java index fb6dca5..af7e5d6 100644 --- a/destributed-key-generation/src/main/java/Communication/Network.java +++ b/destributed-key-generation/src/main/java/Communication/Network.java @@ -28,11 +28,11 @@ public class Network { } } - public User connect(MessageHandler messageHandler){ + public User connect(MailHandler mailHandler){ Integer id = availableIDs.poll(); if (id == null) return null; - users[id - 1] = new User(id,this,new MailHandler(messageHandler)); + users[id - 1] = new User(id,this,mailHandler); return users[id - 1]; } diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java index 2de1ba1..3851b4d 100644 --- a/destributed-key-generation/src/main/java/Communication/User.java +++ b/destributed-key-generation/src/main/java/Communication/User.java @@ -32,7 +32,9 @@ public class User{ public void broadcast(DKGMessages.Mail.Type type, Message message){ network.sendBroadcast(this,type,message); } - + public MailHandler getMailHandler(){ + return mailHandler; + } public void setMessageHandler(MessageHandler messageHandler) { mailHandler.setMessageHandler(messageHandler); } @@ -48,11 +50,7 @@ public class User{ public void run() { while (true){ if (!mailbox.isEmpty()){ - try { - mailHandler.handel(mailbox.poll()); - } catch (InvalidProtocolBufferException e) { - e.printStackTrace(); - } + mailHandler.handel(mailbox.poll()); }else{ try { Thread.sleep(30); diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 51ae86e..521714d 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -58,7 +58,7 @@ public class VerifiableSecretSharing extends SecretSharing { * @param commitments * @param group * - * @return product of commitmentsArray[j] ^ (i ^ j) == g ^ polynomial(i) + * @return product of Aik ^ (j ^ k) == g ^ polynomial(i) */ public static BigInteger verify(int j,BigInteger[] commitments,Group group) { BigInteger v = group.zero(); diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java index bf789f1..b52a728 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -50,8 +50,13 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ } public void sendSecret(User user, int j){ - SecretMessage.Point secret = getShare(j).asMessage(); - user.send(j, Mail.Type.DOUBLE,SecretMessage.newBuilder().setSecret(secret).build()); + ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); + user.send(j, Mail.Type.SECRET, + SecretMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(secret) + .build()); } /** @@ -66,13 +71,13 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ } } - public boolean isValidSecret(int j,BigInteger[] commitments,int i){ - Polynomial.Point secret = shares[j - 1]; - return isValidSecret(secret,commitments,i); + public boolean isValidSecret(int i,BigInteger[] commitments,int j){ + Polynomial.Point secret = shares[i - 1]; + return isValidSecret(secret,commitments,j); } - public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int i){ - BigInteger v = verify(i,commitments,group); + public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ + BigInteger v = verify(j,commitments,group); return group.multiply(g,secret.y).equals(v); } @@ -83,12 +88,12 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ */ public void broadcastComplains(User user, BigInteger[][]commitmentsTable){ ComplaintMessage complaint; - for (int j = 1; j <= n ; j++ ){ - if(j != id) { - if (!isValidSecret(j,commitmentsTable[j - 1],id)) { + for (int i = 1; i <= n ; i++ ){ + if(i != id) { + if (!isValidSecret(i,commitmentsTable[i - 1],id)) { //message = new Message(Type.Complaint, j) complaint = ComplaintMessage.newBuilder() - .setId(j) + .setId(i) .build(); user.broadcast(Mail.Type.COMPLAINT, complaint); } @@ -98,8 +103,10 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ public void broadcastComplaintAnswer(User user, int j){ - user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() - .setSecret(getShare(j).asMessage()) + user.broadcast(Mail.Type.ANSWER, SecretMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) .build()); } @@ -108,10 +115,10 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * if more than t players complain against a player Pi he is disqualified. */ public void answerAllComplainingPlayers(User user, DistributedKeyGenerationUserImpl.ComplainState[] complains){ - for (int j = 1; j <= n ; j++) { - switch (complains[j - 1]) { + for (int i = 1; i <= n ; i++) { + switch (complains[i - 1]) { case Waiting: - broadcastComplaintAnswer(user,j); + broadcastComplaintAnswer(user,i); break; default: break; diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java new file mode 100644 index 0000000..bc2c63e --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java @@ -0,0 +1,46 @@ +package JointFeldmanProtocol; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class DistributedKeyGenerationMailHandler extends MailHandler { + + public DistributedKeyGenerationMailHandler(MessageHandler messageHandler) { + super(messageHandler); + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SECRET: + message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + message = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java index faf0048..43958b2 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -1,9 +1,12 @@ package JointFeldmanProtocol; +import Communication.MailHandler; import Communication.Network; import Communication.User; import ShamirSecretSharing.Polynomial; import UserInterface.DistributedKeyGenerationUser; +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; @@ -39,7 +42,10 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio protected Polynomial.Point share; // final share of the secrete protected BigInteger y; // final public value - public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network) { + public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network){ + this(dkg,network,new DistributedKeyGenerationMailHandler(null)); + } + public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network, MailHandler mailHandler) { this.dkg = dkg; this.g = dkg.getGenerator(); @@ -49,11 +55,12 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio this.id = dkg.getId(); this.messageHandler = new MessageHandler(); + mailHandler.setMessageHandler(this.messageHandler); + this.user = network.connect(mailHandler); this.shares = new Polynomial.Point[n]; this.shares[id - 1] = dkg.getShare(id); this.commitmentsTable = new BigInteger[n][t + 1]; this.doneFlags = new boolean[n]; - this.user = network.connect(messageHandler); this.complaintsTable = new ComplainState[n][n]; for (int i = 0; i < n; i++){ Arrays.fill(complaintsTable[i],ComplainState.Non); @@ -212,75 +219,100 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio this.commitmentsCounter = 0; } - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage) { - if(isBroadcast) { - int i = sender - 1; - int j = complaintMessage.getId() - 1; - switch (complaintsTable[i][j]) { - case Non: - complaintsTable[i][j] = ComplainState.Waiting; - break; - default: - break; - } - } + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage){ + int i = sender; + int j = complaintMessage.getId(); + return isBroadcast && complaintsTable[i - 1][j - 1].equals( ComplainState.Non); } @Override - public void handelDoneMessage(int sender, boolean isBroadcast, DKGMessages.DoneMessage doneMessage) { - if(isBroadcast && !doneFlags[sender - 1]) { + public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.ComplaintMessage complaintMessage = (DKGMessages.ComplaintMessage)message; + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + complaintsTable[i - 1][j - 1] = ComplainState.Waiting; + } + } + + protected boolean isValidDoneMessage(int sender, boolean isBroadcast){ + return isBroadcast && !doneFlags[sender - 1]; + } + + @Override + public void handelDoneMessage(int sender, boolean isBroadcast,Message message) { + if(isValidDoneMessage(sender,isBroadcast)) { doneFlags[sender - 1] = true; doneCounter++; } } + protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage){ + int i = sender - 1; + int k = commitmentMessage.getK(); + return isBroadcast && commitmentsTable[i][k] == null; + } + @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - if(isBroadcast){ + public void handelCommitmentMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; + if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ int i = sender - 1; int k = commitmentMessage.getK(); - if(commitmentsTable[i][k] == null){ - commitmentsTable[i][k] = extractCommitment(commitmentMessage); - commitmentsCounter++; - } + commitmentsTable[i][k] = extractCommitment(commitmentMessage); + commitmentsCounter++; } } + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage){ + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + if(sender != i || isBroadcast) + return false; + else + return shares[i - 1] == null && j == id; + + } + @Override - public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { - Polynomial.Point secret = extractSecret(secretMessage); - if(!isBroadcast){ - if(shares[sender - 1] == null) { - shares[sender - 1] = secret; - secretsCounter++; - } - }else { - int i = sender; - int j = secret.x.intValue(); - switch (complaintsTable[i - 1][j - 1]){ - case Waiting: - if(dkg.isValidSecret(secret,commitmentsTable[i - 1],j)){ - complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; - }else{ - complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; - } - break; - default: - break; - } + public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; + if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + Polynomial.Point secret = extractSecret(i,secretMessage.getSecret()); + shares[i - 1] = secret; + secretsCounter++; } } + protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage){ + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + if(sender != i || !isBroadcast) + return false; + else + return j >= 1 && j <= n && complaintsTable[i - 1][j - 1].equals(ComplainState.Waiting); + } + @Override - public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - + public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; + if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + Polynomial.Point secret = extractSecret(i,secretMessage.getSecret()); + if (dkg.isValidSecret(secret, commitmentsTable[i - 1], j)) + complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + else + complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + } } - public Polynomial.Point extractSecret(DKGMessages.SecretMessage secretMessage){ - return new Polynomial.Point(secretMessage.getSecret()); + public Polynomial.Point extractSecret(int i, ByteString secret){ + BigInteger x = BigInteger.valueOf(i); + BigInteger y = new BigInteger(secret.toByteArray()); + return new Polynomial.Point(x,y); } - public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ return new BigInteger(commitmentMessage.getCommitment().toByteArray()); } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java deleted file mode 100644 index 02ae13e..0000000 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGenerationUserImpl.java +++ /dev/null @@ -1,138 +0,0 @@ -package SecureDistributedKeyGeneration; - -import Communication.Network; -import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; -import ShamirSecretSharing.Polynomial; -import meerkat.protobuf.DKGMessages; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 2/22/2016. - */ -public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { - - private final SecureDistributedKeyGeneration sdkg; - - private final Polynomial.Point[] sharesT; - private final BigInteger[][] verificationValuesTable; - - public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { - super(sdkg, network); - this.sdkg = sdkg; - this.sharesT = new Polynomial.Point[n]; - this.verificationValuesTable = new BigInteger[n][t + 1]; - this.messageHandler = new MessageHandler(); - this.user.setMessageHandler(this.messageHandler); - } - - /** - * 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.broadcastVerificationValues(user); - sdkg.sendSecrets(user); - } - - /** - * 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.setShares(shares); - sdkg.setSharesT(sharesT); - sdkg.broadcastComplains(user,verificationValuesTable); - //broadcast done message after all complaints - DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - } - - private void ys(){ - sdkg.broadcastCommitments(user); - //wait for receive all commitments from all i in QUAL - for (int i:QUAL) { - for(int k = 0; k <= t; k++) { - while (commitmentsTable[i - 1][k] == null) { - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - sdkg.broadcastComplaints(user,commitmentsTable,true); - //do something with complaints' answers - - } - - @Override - protected void stage4() { - ys(); - super.stage4(); - } - - private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ - - final int NumberOfCommitmentsInStage1 = n * (t + 1); - - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - if(isBroadcast){ - if(commitmentsCounter < NumberOfCommitmentsInStage1){ - int i = sender - 1; - int k = commitmentMessage.getK(); - if(verificationValuesTable[i][k] == null){ - verificationValuesTable[i][k] = extractCommitment(commitmentMessage); - commitmentsCounter++; - } - } else{ - super.handelCommitmentMessage(sender,isBroadcast,commitmentMessage); - } - } - } - - @Override - public void handelSecretMessage(int sender, boolean isBroadcast, DKGMessages.SecretMessage secretMessage) { - //there is no secret message in this protocol - } - - @Override - public void handelDoubleSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - - Polynomial.Point secret = extractSecret(doubleSecretMessage.getS1()); - Polynomial.Point secretT = extractSecret(doubleSecretMessage.getS2()); - if(!isBroadcast){ - if(shares[sender - 1] == null) { - shares[sender - 1] = secret; - sharesT[sender - 1] = secretT; - secretsCounter++; - } - }else { - if(commitmentsCounter <= NumberOfCommitmentsInStage1) { - int i = sender; - int j = secret.x.intValue(); - switch (complaintsTable[i - 1][j - 1]) { - case Waiting: - if (sdkg.isValidSecret(secret,secretT, verificationValuesTable[j - 1], i)) { - complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; - } else { - complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; - } - break; - default: - break; - } - }else{ // stage4 - - } - } - } - } -} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java similarity index 53% rename from destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java rename to destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java index bd204c8..05e892e 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGeneration/SecureDistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java @@ -1,6 +1,5 @@ -package SecureDistributedKeyGeneration; +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; -import Communication.Network; import Communication.User; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; import JointFeldmanProtocol.DistributedKeyGeneration; @@ -8,7 +7,6 @@ import ShamirSecretSharing.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; -import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; import java.util.Random; @@ -32,31 +30,34 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { @Override public void sendSecret(User user,int j) { - DKGMessages.SecretMessage.Point secret = getShare(j).asMessage();; - DKGMessages.SecretMessage.Point secretT = verifiableSecretSharing.getShare(j).asMessage();; - DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() - .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secret).build()) - .setS2(DKGMessages.SecretMessage.newBuilder().setSecret(secretT).build()) - .build(); - user.send(j, DKGMessages.Mail.Type.DOUBLE, doubleSecretMessage); + Polynomial.Point secret = getShare(j); + Polynomial.Point secretT = verifiableSecretSharing.getShare(j); + DKGMessages.DoubleSecretMessage doubleSecretMessage = doubleSecretMessage(id,j,secret,secretT); + user.send(j, DKGMessages.Mail.Type.SECRET, doubleSecretMessage); } @Override - public boolean isValidSecret(int j, BigInteger[] commitments, int i){ - Polynomial.Point secret = shares[j - 1]; - Polynomial.Point secretT = sharesT[j - 1]; - return isValidSecret(secret,secretT,commitments,i); + public boolean isValidSecret(int i, BigInteger[] commitments, int j){ + Polynomial.Point secret = shares[i - 1]; + Polynomial.Point secretT = sharesT[i - 1]; + return isValidSecret(secret,secretT,commitments, j); } - public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int i){ - BigInteger v = verify(i,verificationValues,group); + public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int j){ + BigInteger v = verify(j,verificationValues,group); BigInteger exp = group.add(group.multiply(g, secret.y),group.multiply(h, secretT.y)); return exp.equals(v); } - public boolean isValidComplaint(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] commitments - ,BigInteger[] verificationValues, int i){ - return isValidSecret(secret,secretT,verificationValues,i) && !isValidSecret(secret,commitments,i); + + public void broadcastComplaint(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ + DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); + user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); + } + + public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ + DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); + user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); } /** @@ -67,10 +68,10 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { if(!stage4){ broadcastComplains(user,commitmentsTable); }else{ - for (int j = 1; j <= n ; j++ ){ - if(j != id) { - if (!isValidSecret(shares[j - 1],commitmentsTable[j - 1],id)) { - broadcastDoubleSecret(user,shares[j - 1],sharesT[j - 1]); + for (int i = 1; i <= n ; i++ ){ + if(i != id) { + if (!isValidSecret(shares[i - 1],commitmentsTable[i - 1],id)) { + broadcastComplaint(user,shares[i - 1],sharesT[i - 1],i); } } } @@ -87,19 +88,21 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { broadcastCommitments(user,verificationValues); } - private void broadcastDoubleSecret(User user ,Polynomial.Point secret, Polynomial.Point secretT){ - DKGMessages.SecretMessage.Point secretMessage = secret.asMessage(); - DKGMessages.SecretMessage.Point secretTMessage = secretT.asMessage(); + private DKGMessages.DoubleSecretMessage doubleSecretMessage(int i,int j,Polynomial.Point secret, Polynomial.Point secretT){ DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() - .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secretMessage).build()) - .setS1(DKGMessages.SecretMessage.newBuilder().setSecret(secretTMessage).build()) + .setI(i) + .setJ(j) + .setSecret(ByteString.copyFrom(secret.y.toByteArray())) + .setSecretT(ByteString.copyFrom(secretT.y.toByteArray())) .build(); - user.broadcast(DKGMessages.Mail.Type.DOUBLE, doubleSecretMessage); + return doubleSecretMessage; } @Override public void broadcastComplaintAnswer(User user, int j) { - broadcastDoubleSecret(user,getShare(j),verifiableSecretSharing.getShare(j)); + DKGMessages.DoubleSecretMessage answer = doubleSecretMessage(id,j,getShare(j) + ,verifiableSecretSharing.getShare(j)); + user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); } public void setSharesT(Polynomial.Point[] sharesT) { diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java new file mode 100644 index 0000000..2f60c6d --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java @@ -0,0 +1,60 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class SecureDistributedKeyGenerationMailHandler extends MailHandler { + + private boolean isStage4; + + public SecureDistributedKeyGenerationMailHandler(MessageHandler messageHandler) { + super(messageHandler); + this.isStage4 = false; + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SECRET: + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + if(isStage4) + message = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); + else + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } + + public boolean isStage4() { + return isStage4; + } + + public void setStage4(boolean stage4) { + isStage4 = stage4; + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java new file mode 100644 index 0000000..e8fcf9d --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java @@ -0,0 +1,247 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + +/** + * Created by Tzlil on 2/22/2016. + */ +public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { + + private final SecureDistributedKeyGeneration sdkg; + private final Polynomial.Point[] sharesT; + private final BigInteger[][] verificationValuesTable; + private final Hashtable> ysRestoreShares; + + public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { + super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); + this.sdkg = sdkg; + this.sharesT = new Polynomial.Point[n]; + this.verificationValuesTable = new BigInteger[n][t + 1]; + this.ysRestoreShares = new Hashtable>(); + this.messageHandler = new MessageHandler(); + this.user.setMessageHandler(this.messageHandler); + } + + /** + * 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.broadcastVerificationValues(user); + sdkg.sendSecrets(user); + } + + /** + * 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.setShares(shares); + sdkg.setSharesT(sharesT); + sdkg.broadcastComplains(user,verificationValuesTable); + //broadcast done message after all complaints + DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + } + + private void ys(){ + sdkg.broadcastCommitments(user); + //wait for receive all commitments from all i in QUAL + for (int i:QUAL) { + for(int k = 0; k <= t; k++) { + while (commitmentsTable[i - 1][k] == null) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + sdkg.broadcastComplaints(user,commitmentsTable,true); + //broadcast done message after all complaints + DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + + for (int i:QUAL) { + while (doneFlags[i - 1]) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + BigInteger secret; + for (Integer i: ysRestoreShares.keySet()) { + try { + secret = SecretSharing.restoreSecret((Polynomial.Point[])ysRestoreShares.get(i).toArray()); + //ToDo use restored secret... + } catch (Exception e) { + // + } + } + } + + @Override + protected void stage4() { + isStage4 = true; + ((SecureDistributedKeyGenerationMailHandler)user.getMailHandler()).setStage4(true); + ys(); + super.stage4(); + } + boolean isStage4 = false; + private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ + + final int NumberOfCommitmentsInStage1 = n * (t + 1); + + @Override + protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { + if(commitmentsCounter < NumberOfCommitmentsInStage1) { + int i = sender - 1; + int k = commitmentMessage.getK(); + return isBroadcast && verificationValuesTable[i][k] == null; + }else { + return super.isValidCommitmentMessage(sender, isBroadcast, commitmentMessage); + } + } + + @Override + public void handelCommitmentMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.CommitmentMessage commitmentMessage = ( DKGMessages.CommitmentMessage)message; + if(commitmentsCounter < NumberOfCommitmentsInStage1) { + if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)) { + int i = sender - 1; + int k = commitmentMessage.getK(); + verificationValuesTable[i][k] = extractCommitment(commitmentMessage); + commitmentsCounter++; + } + } + else{ + super.handelCommitmentMessage(sender,isBroadcast,commitmentMessage); + } + } + + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidSecretMessage(sender,isBroadcast,secretMessage); + } + + @Override + public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; + if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + + Polynomial.Point secret = extractSecret(i, doubleSecretMessage.getSecret()); + Polynomial.Point secretT = extractSecret(i, doubleSecretMessage.getSecretT()); + shares[i - 1] = secret; + sharesT[i - 1] = secretT; + secretsCounter++; + } + } + protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + if(!isStage4) { + DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); + }else{ + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j)&& ysRestoreShares.containsKey(i); + } + } + + @Override + public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; + if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + Polynomial.Point secret = extractSecret(i, doubleSecretMessage.getSecret()); + Polynomial.Point secretT = extractSecret(i, doubleSecretMessage.getSecretT()); + if (!isStage4) { + if (sdkg.isValidSecret(secret, secretT, verificationValuesTable[j - 1], i)) { + complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + } else { + complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + } + } else { + if (ysRestoreShares.get(i).add(secret) && sender != id) { + sdkg.broadcastAnswer(user, secret, secretT, i); + } + } + } + } + + @Override + protected boolean isValidDoneMessage(int sender, boolean isBroadcast) { + if(doneCounter < n) { + return super.isValidDoneMessage(sender, isBroadcast); + }else{ + return isBroadcast && doneFlags[sender - 1]; + } + } + + @Override + public void handelDoneMessage(int sender, boolean isBroadcast, Message message) { + if(doneCounter < n) + super.handelDoneMessage(sender, isBroadcast, message); + else{ + if(isValidDoneMessage(sender,isBroadcast)) { + doneFlags[sender - 1] = false; + } + } + } + + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, + DKGMessages.DoubleSecretMessage ysComplaintMessage){ + int i = ysComplaintMessage.getI(); + int j = ysComplaintMessage.getJ(); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j)&&!ysRestoreShares.containsKey(i); + } + + @Override + public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { + if(!isStage4) { + super.handelComplaintMessage(sender, isBroadcast, message); + }else { + DKGMessages.DoubleSecretMessage ysComplaintMessage =(DKGMessages.DoubleSecretMessage)message; + if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { + int i = ysComplaintMessage.getI(); + int j = ysComplaintMessage.getJ(); + Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); + Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); + if (sdkg.isValidSecret(secret, secretT, verificationValuesTable[i - 1], j) + && !sdkg.isValidSecret(secret, commitmentsTable[i - 1], j)) { + ysRestoreShares.put(i, new HashSet()); + ysRestoreShares.get(i).add(secret); + sdkg.broadcastAnswer(user, secret, secretT, i); + } + } + } + } + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index 1c8eb0e..cf8719f 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -199,15 +199,6 @@ public class Polynomial implements Comparable { this.y = polynomial.image(x); } - /** - * constructor - restore point from message - * @param pointMessage - */ - public Point(DKGMessages.SecretMessage.Point pointMessage) { - this.x = new BigInteger(pointMessage.getX().toByteArray()); - this.y = new BigInteger(pointMessage.getY().toByteArray()); - } - /** * constructor * @param x @@ -217,14 +208,6 @@ public class Polynomial implements Comparable { this.x = x; this.y = y; } - - public DKGMessages.SecretMessage.Point asMessage(){ - return DKGMessages.SecretMessage.Point.newBuilder() - .setX(ByteString.copyFrom(x.toByteArray())) - .setY(ByteString.copyFrom(y.toByteArray())) - .build(); - } - } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 7dc0bca..7b6133f 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -66,7 +66,7 @@ public class SecretSharing{ * * @return image of interpolation(shares) at x = 0 */ - public static BigInteger restoreSecrete(Polynomial.Point[] shares) throws Exception { + public static BigInteger restoreSecret(Polynomial.Point[] shares) throws Exception { Polynomial polynomial = Polynomial.interpolation(shares); return polynomial.image(BigInteger.ZERO); } diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index 4000ec0..066daff 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -99,7 +99,7 @@ public class DKGTest { // index = indexes.remove(random.nextInt(indexes.size())); // shares[i] = dkgs[index - 1].getShare(); //} - BigInteger calculatedSecret = SecretSharing.restoreSecrete(shares).mod(q); + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares).mod(q); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/SDKGTest.java b/destributed-key-generation/src/test/java/SDKGTest.java index 09bfc2e..e295099 100644 --- a/destributed-key-generation/src/test/java/SDKGTest.java +++ b/destributed-key-generation/src/test/java/SDKGTest.java @@ -1,7 +1,7 @@ import Communication.Network; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import SecureDistributedKeyGeneration.SecureDistributedKeyGeneration; -import SecureDistributedKeyGeneration.SecureDistributedKeyGenerationUserImpl; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; import UserInterface.DistributedKeyGenerationUser; @@ -99,7 +99,7 @@ public class SDKGTest { // index = indexes.remove(random.nextInt(indexes.size())); // shares[i] = dkgs[index - 1].getShare(); //} - BigInteger calculatedSecret = SecretSharing.restoreSecrete(shares).mod(q); + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares).mod(q); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java index 8c73ee0..14aa387 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java @@ -1,6 +1,5 @@ package ShamirSecretSharing; -import Communication.Network; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; import org.junit.Before; @@ -50,7 +49,7 @@ public class SecretSharingTest { for (int i = 0 ; i < shares.length ; i++){ shares[i] = secretSharing.getShare(indexes.remove(random.nextInt(indexes.size()))); } - assert(secret.equals(SecretSharing.restoreSecrete(shares))); + assert(secret.equals(SecretSharing.restoreSecret(shares))); } @Test diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto index 4fbc4da..70d5808 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -8,9 +8,12 @@ message Mail{ enum Type { SECRET = 0; COMMITMENT = 1; - DONE = 2; - COMPLAINT = 3; - DOUBLE = 4; + COMPLAINT = 2; + DONE = 3; + ANSWER = 4; + YCOMMITMENT = 5; + YCOMPLAINT = 6; + YANSWER = 7; } int32 sender = 1; int32 destination = 2; @@ -20,16 +23,16 @@ message Mail{ } message SecretMessage { - message Point{ - bytes x = 1; - bytes y = 2; - } - Point secret = 1; + int32 i = 1; + int32 j = 2; + bytes secret = 3; } message DoubleSecretMessage{ - SecretMessage s1 = 1; - SecretMessage s2 = 2; + int32 i = 1; + int32 j = 2; + bytes secret = 3; + bytes secretT = 4; } message CommitmentMessage{ @@ -41,4 +44,4 @@ message DoneMessage{} message ComplaintMessage{ int32 id = 1; -} \ No newline at end of file +} From 15453a772d4e23d4ab6718caafbd2eae28e4882e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 2 Mar 2016 19:52:17 +0200 Subject: [PATCH 026/106] Changes made in the initial interfaces for further code review. 1. Especially tried to fix the callback mechanism I previously used. 2. 'long sessionID' changed to 'int requestId' 3. Introduced a generic class VotingBoothResult 4. Quite some other local changes --- .../src/main/proto/meerkat/voting.proto | 4 +- .../meerkat/voting/BallotOutputDevice.java | 18 +++-- .../java/meerkat/voting/StorageManager.java | 7 +- .../src/main/java/meerkat/voting/UI.java | 32 --------- .../main/java/meerkat/voting/VotingBooth.java | 71 +++---------------- ...cryptor.java => VotingBoothEncryptor.java} | 4 +- .../meerkat/voting/VotingBoothResult.java | 17 +++++ .../java/meerkat/voting/VotingBoothUI.java | 64 +++++++++++++++++ 8 files changed, 111 insertions(+), 106 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/UI.java rename voting-booth/src/main/java/meerkat/voting/{Encryptor.java => VotingBoothEncryptor.java} (61%) create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 759a708..8b49ca9 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -28,7 +28,9 @@ message UIElement { bytes data = 2; } -// a new data structure for BallotQuestion. Need to delete the old one +// A question in the ballot +// is_mandatory determines whether the question may be skipped with no answer +// description might hold information/guidlines for the voter message BallotQuestion { bool is_mandatory = 1; UIElement question = 2; diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java index 32e3208..39eed6a 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -1,5 +1,6 @@ package meerkat.voting; +import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** @@ -7,13 +8,20 @@ import meerkat.protobuf.Voting.*; */ public interface BallotOutputDevice { - void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback); + /** + * + * @param requestId + * @param encryptedBallot + * @param callback + */ + void commitToBallot(int requestId, EncryptedBallot encryptedBallot, + FutureCallback> callback); - void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback); + void audit(int requestId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, + FutureCallback> callback); - void castBallot(long sessionId, VotingBooth.Callback callback); + void castBallot(int requestId, FutureCallback> callback); - // probably has no difference than cast. Maybe drop this method - void cancelBallot(long sessionId, VotingBooth.Callback callback); + void cancelBallot(int requestId, FutureCallback> callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java index 3edff7a..c05f383 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -1,12 +1,13 @@ package meerkat.voting; +import meerkat.protobuf.Voting; + /** * Created by hai on 23/02/16. */ public interface StorageManager { - // should these methods be synchronous or asynchronous? Can we rely on it being immediate? - public void detectAdminHardwareKey(); + boolean detectAdminHardwareKey(); - public void readElectionParams (); + Voting.ElectionParams readElectionParams (); } diff --git a/voting-booth/src/main/java/meerkat/voting/UI.java b/voting-booth/src/main/java/meerkat/voting/UI.java deleted file mode 100644 index 83739db..0000000 --- a/voting-booth/src/main/java/meerkat/voting/UI.java +++ /dev/null @@ -1,32 +0,0 @@ -package meerkat.voting; - -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 23/02/16. - */ -public interface UI { - - - // Voter scenario methods - void introductionToVoter (long sessionId); - - void chooseChannel (long sessionId, BallotQuestion question); - - void askVoterQuestion (long sessionId, int questionNumber, BallotQuestion question); - - void castOrAudit (long sessionId); - - void showWaitForFinishScreen (long sessionId); - - - // Admin scenario methods - //TODO: the admin scenario still needs some more thinking - - - - // bad thing happened scenario - void showErrorMessageAndHalt (String errorMessage); - void showErrorMessageWithCancelButton (long sessionId, String errorMessage); - -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index a7df483..9182eca 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -1,6 +1,5 @@ package meerkat.voting; -import meerkat.protobuf.Voting; import meerkat.protobuf.Voting.*; /** @@ -8,75 +7,21 @@ import meerkat.protobuf.Voting.*; */ public interface VotingBooth { - public enum ErrorID { - OUTPUT_DEVICE_OUT_OF_PAPER, - OUTPUT_DEVICE_OUT_OF_INK, - OUTPUT_DEVICE_NO_CONNECTION, - OUTPUT_DEVICE_HARDWARE_NOT_FOUND, + void setComponenets (BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); - UI_HARDWARE_NOT_FOUND - } + void initBoothParams (BoothParams boothParams); - - // keeps track in which state we are - // internal state will also include the number of the current question and the answers we got so far, - // later it includes the details of the PlaintextBallot and later the Encryption and the secrets - public enum State { - INITIALIZED, - - VOTER_INTRODUCTION, - VOTER_CHOOSE_CHANNEL, - VOTER_VOTING, - VOTER_ENCRYPTING, - VOTER_CAST_OR_AUDIT, - VOTER_CASTING, - VOTER_AUDITING - - } - - public interface Callback { - - // callbacks and messages from BallotOutputDevice - - public void ballotCommitResult (long sessionId, boolean result); - public void ballotCastResult (long sessionId, boolean result); - public void ballotAuditResult (long sessionId, boolean result); - public void ballotCancelResult (long sessionId, boolean result); - // other error messages, such as Printer turned-off or out-of-paper - public void outputDeviceReportProblem (ErrorID errorId); - - - // callbacks and messages from UI - - public void introductionFinished (long sessionId); - public void choiceOfChannel (long sessionId, int channelNumber); - public void skipQuestion (long sessionId, int questionNumber); - public void backwardsQuestion (long sessionId, int questionNumber); - public void cancelVotingSession (long sessionId); - public void answer (long sessionId, int questionNumber, String answer); - public void cast (long sessionId); - public void audit (long sessionId); - // other error messages, such as hardware-not-detected - public void uiReportProblem (ErrorID errorId); - - - // callbacks from encryptor - - public void returnEncryption (long sessionId, EncryptedBallot encryptedBallot, BallotSecrets secrets); - - - // callbacks from StorageManager - - public void adminHardwareKeyDetected (boolean isKeyInserted); - public void loadElectionParams (ElectionParams electionParams); - } + void initElectionParams (ElectionParams electionParams); // this function is synchronous - public void start (); + void start (); // messages from Admin Console (If there is such one) // this function is asynchronous - public void shutDown(); + void shutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/Encryptor.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java similarity index 61% rename from voting-booth/src/main/java/meerkat/voting/Encryptor.java rename to voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java index 4cfcf57..60384e9 100644 --- a/voting-booth/src/main/java/meerkat/voting/Encryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java @@ -5,9 +5,9 @@ import meerkat.protobuf.Voting.*; /** * Created by hai on 23/02/16. */ -public interface Encryptor { +public interface VotingBoothEncryptor { - public void encrypt (long sessionId, PlaintextBallot plaintextBallot); + void encrypt (PlaintextBallot plaintextBallot); //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java new file mode 100644 index 0000000..6702ce9 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java @@ -0,0 +1,17 @@ +package meerkat.voting; + +/** + * Created by hai on 02/03/16. + */ +public class VotingBoothResult { + private final int m_requestId; + private final T m_result; + + public int getRequestId () { return m_requestId; } + public T getResult () { return m_result; } + + public VotingBoothResult (int requestId, T result) { + m_requestId = requestId; + m_result = result; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java new file mode 100644 index 0000000..0726a09 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -0,0 +1,64 @@ +package meerkat.voting; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 23/02/16. + */ +public interface VotingBoothUI { + + enum VoterQuestionChoice { + ANSWERED, + SKIP, + BACK, + CANCEL + } + + class VoterQuestionResponse { + private final VoterQuestionChoice m_choice; + private final String m_answer; + + public VoterQuestionResponse(VoterQuestionChoice choice, String answer) { + assert ((choice == VoterQuestionChoice.ANSWERED && answer != null) || + (choice != VoterQuestionChoice.ANSWERED && answer == null)); + m_choice = choice; + m_answer = answer; + } + + public VoterQuestionChoice getChoice () { return m_choice; } + public String getAnswer () { return m_answer; } + } + + + enum FinalizeBallotChoice { + CAST, + AUDIT + } + + // Voter scenario methods + void newVoter (int requestId, FutureCallback> callback); + + void chooseChannel (int requestId, BallotQuestion question, FutureCallback> callback); + + void askVoterQuestion (int requestId, int questionNumber, BallotQuestion question, + FutureCallback> callback); + + void castOrAudit (int requestId, FutureCallback> callback); + + void showWaitForFinishScreen (int requestId, FutureCallback> callback); + + + // Admin scenario methods + //TODO: the admin scenario still needs some more thinking + + + + // bad thing happened scenario + void showErrorMessageAndHalt (int requestId, String errorMessage, + FutureCallback> callback); + + void showErrorMessageWithButtons (int requestId, String errorMessage, String[] buttonLabels, + FutureCallback> callback); + +} From 0fa5d4094add0f4fc20a53ce2d54979ddf8537b8 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 13 Mar 2016 15:35:58 +0200 Subject: [PATCH 027/106] yet another take on the VB interfaces. Interfaces were now shortened even more. Many changes were made according to Arbel's instructions. Most important change is now that the controller passes ALL questions for UI to ask voter, instead of chunks of questions and back-and-forth messages between the controller and UI which were always quite redundant. --- .../meerkat/voting/BallotOutputDevice.java | 34 +++++--- .../java/meerkat/voting/StorageManager.java | 16 +++- .../main/java/meerkat/voting/VotingBooth.java | 37 ++++++--- .../meerkat/voting/VotingBoothEncryptor.java | 28 ++++++- .../meerkat/voting/VotingBoothResult.java | 17 ---- .../java/meerkat/voting/VotingBoothUI.java | 79 ++++++++++--------- 6 files changed, 131 insertions(+), 80 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java index 39eed6a..0199523 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java @@ -4,24 +4,36 @@ import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** - * Created by hai on 15/02/16. + * An interface for the device in which we output the ballots. + * Probably going to be a printer or an ethernet connection, or both. */ public interface BallotOutputDevice { /** - * - * @param requestId - * @param encryptedBallot - * @param callback + * Output the encrypted ballot. This is a commitment before voter chooses casting or auditing + * @param encryptedBallot - the encrypted ballot to commit to + * @param callback - a callback object through which to return a success flag */ - void commitToBallot(int requestId, EncryptedBallot encryptedBallot, - FutureCallback> callback); + public void commitToBallot(EncryptedBallot encryptedBallot, FutureCallback callback); - void audit(int requestId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, - FutureCallback> callback); + /** + * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. + * @param encryptedBallot - the encrypted ballot + * @param ballotSecrets - the secrtes of the encryption + * @param callback - a callback object through which to return a success flag + */ + public void audit(EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, FutureCallback callback); - void castBallot(int requestId, FutureCallback> callback); + /** + * Voter chose 'cast'. Finalize the ballot for use in the polling station + * @param callback - a callback object through which to return a success flag + */ + public void castBallot(FutureCallback callback); - void cancelBallot(int requestId, FutureCallback> callback); + /** + * Cancelling the current ballot. This clears the state of the OutputDevice if the implementation has any such state. + * @param callback - a callback object through which to return a success flag + */ + public void cancelBallot(FutureCallback callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/StorageManager.java index c05f383..0fd18ca 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/StorageManager.java @@ -1,13 +1,21 @@ package meerkat.voting; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the storage component of the voting booth */ public interface StorageManager { - boolean detectAdminHardwareKey(); + /** + * Detect whether an administration key is inserted to the machine. This determines if we gointo the set-up flow or the voting session flow. + * @return True is a hardware key is inserted. False if not. + */ + public boolean isAdminHardwareKeyInserted(); - Voting.ElectionParams readElectionParams (); + /** + * load the election params from a file. + * @return the current election params + */ + public ElectionParams readElectionParams (); } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index 9182eca..a2b211b 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -3,25 +3,42 @@ package meerkat.voting; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the controller component of the voting booth */ public interface VotingBooth { - void setComponenets (BallotOutputDevice outputDevice, + /** + * setting all the different components of the Voting Booth to be recognized by this controller + * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection + * @param vbEncryptor the encryption module + * @param vbUI User interface in which the voter chooses his answers + * @param vbStorageManager storage component for handling files and USB sticks + */ + public void setComponenets (BallotOutputDevice outputDevice, VotingBoothEncryptor vbEncryptor, VotingBoothUI vbUI, StorageManager vbStorageManager); - void initBoothParams (BoothParams boothParams); + /** + * initialize using the BoothParams protobuf + * @param boothParams + */ + public void initBoothParams (BoothParams boothParams); - void initElectionParams (ElectionParams electionParams); + /** + * set the voting questions + * @param questions + */ + public void setBallotQuestions (BallotQuestion[] questions); - // this function is synchronous - void start (); + /** + * a synchronous function. Starts running the controller component, and basically run the whole system for voting + */ + public void run (); - - // messages from Admin Console (If there is such one) - // this function is asynchronous - void shutDown(); + /** + * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system + */ + public void shutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java index 60384e9..cc9b7bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java @@ -1,13 +1,37 @@ package meerkat.voting; +import com.sun.org.apache.xml.internal.security.encryption.EncryptedType; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the encryptor component of the voting booth */ public interface VotingBoothEncryptor { - void encrypt (PlaintextBallot plaintextBallot); + /** + * A simple class for pairing EncrypedBallot together with its matching BallotSecrets + */ + public class EncryptionAndSecrets { + private final EncryptedBallot encryptedBallot; + private final BallotSecrets secrets; + + public EncryptionAndSecrets (EncryptedBallot encryptedBallot, BallotSecrets secrets) { + this.encryptedBallot = encryptedBallot; + this.secrets = secrets; + } + + public EncryptedBallot getEncryptedBallot () { return encryptedBallot; } + public BallotSecrets getSecrets() { return secrets; } + } + + + /** + * This function encrypts the plaintext ballot using the booth's keys + * @param plaintextBallot - all plaintext ballot info of the voter + * @return an encryption of the ballot + */ + public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot); + //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java deleted file mode 100644 index 6702ce9..0000000 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothResult.java +++ /dev/null @@ -1,17 +0,0 @@ -package meerkat.voting; - -/** - * Created by hai on 02/03/16. - */ -public class VotingBoothResult { - private final int m_requestId; - private final T m_result; - - public int getRequestId () { return m_requestId; } - public T getResult () { return m_result; } - - public VotingBoothResult (int requestId, T result) { - m_requestId = requestId; - m_result = result; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java index 0726a09..78ccfef 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -4,61 +4,68 @@ import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; /** - * Created by hai on 23/02/16. + * An interface for the user interface component of the voting booth */ public interface VotingBoothUI { - enum VoterQuestionChoice { - ANSWERED, - SKIP, - BACK, - CANCEL - } - - class VoterQuestionResponse { - private final VoterQuestionChoice m_choice; - private final String m_answer; - - public VoterQuestionResponse(VoterQuestionChoice choice, String answer) { - assert ((choice == VoterQuestionChoice.ANSWERED && answer != null) || - (choice != VoterQuestionChoice.ANSWERED && answer == null)); - m_choice = choice; - m_answer = answer; - } - - public VoterQuestionChoice getChoice () { return m_choice; } - public String getAnswer () { return m_answer; } - } - - enum FinalizeBallotChoice { CAST, AUDIT } - // Voter scenario methods - void newVoter (int requestId, FutureCallback> callback); + /** + * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning + * @param callback - a boolean future callback to return success when done + */ + public void startNewVoterSession (FutureCallback callback); - void chooseChannel (int requestId, BallotQuestion question, FutureCallback> callback); + /** + * Present a question to the voter to decide on his voting channel. + * @param question a question to determine the right voting channel for this voter + * @param callback that's where we store the channel for the current voter + */ + public void chooseChannel (BallotQuestion question, FutureCallback callback); - void askVoterQuestion (int requestId, int questionNumber, BallotQuestion question, - FutureCallback> callback); + /** + * Presents the set of questions to the voter. Collect all his responses. + * @param questions all ballot questions to present to the voter + * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session + */ + public void askVoterQuestions (BallotQuestion[] questions, FutureCallback callback); - void castOrAudit (int requestId, FutureCallback> callback); + /** + * Get a response from the voter on how to finalize the ballot. + * @param callback the returned choice of how to finalize the ballot + */ + public void castOrAudit (FutureCallback callback); - void showWaitForFinishScreen (int requestId, FutureCallback> callback); // Admin scenario methods //TODO: the admin scenario still needs some more thinking + /** + * present a wait-for-finish screen to the voter + * @param message a message to show the user on the UI device while waiting + * @param callback a success return value of the wait (cancelling returns false) + */ + public void askVoterToWaitForFinish (String message, FutureCallback callback); - // bad thing happened scenario - void showErrorMessageAndHalt (int requestId, String errorMessage, - FutureCallback> callback); + /** + * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset + * @param errorMessage message to show in UI device + * @param callback returns interrupt + */ + public void showErrorMessageAndHalt (String errorMessage, FutureCallback callback); - void showErrorMessageWithButtons (int requestId, String errorMessage, String[] buttonLabels, - FutureCallback> callback); + /** + * show an error message and let user press his chosen button for continuation + * @param errorMessage message to show in UI device + * @param buttonLabels labels for buttons to present to voter + * @param callback the number of the selected button + */ + public void showErrorMessageWithButtons (String errorMessage, String[] buttonLabels, + FutureCallback callback); } From d1bc0d7c844d1facfbea85d2df48fef3e5cf42a2 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Fri, 18 Mar 2016 10:22:05 +0200 Subject: [PATCH 028/106] Some small changes according to code review --- .../main/java/meerkat/voting/VotingBooth.java | 18 +++++++----------- .../java/meerkat/voting/VotingBoothUI.java | 10 +++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java index a2b211b..9ef863c 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java @@ -8,22 +8,18 @@ import meerkat.protobuf.Voting.*; public interface VotingBooth { /** - * setting all the different components of the Voting Booth to be recognized by this controller + * initialize using the BoothParams protobuf and sett all the different components of the Voting Booth to be recognized by this controller + * @param boothParams * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection * @param vbEncryptor the encryption module * @param vbUI User interface in which the voter chooses his answers * @param vbStorageManager storage component for handling files and USB sticks */ - public void setComponenets (BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, - VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * initialize using the BoothParams protobuf - * @param boothParams - */ - public void initBoothParams (BoothParams boothParams); + public void init (BoothParams boothParams, + BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); /** * set the voting questions diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java index 78ccfef..c2ccfea 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java @@ -8,7 +8,7 @@ import meerkat.protobuf.Voting.*; */ public interface VotingBoothUI { - enum FinalizeBallotChoice { + public static enum FinalizeBallotChoice { CAST, AUDIT } @@ -24,7 +24,7 @@ public interface VotingBoothUI { * @param question a question to determine the right voting channel for this voter * @param callback that's where we store the channel for the current voter */ - public void chooseChannel (BallotQuestion question, FutureCallback callback); + public void chooseChannel (BallotQuestion question, FutureCallback callback); /** * Presents the set of questions to the voter. Collect all his responses. @@ -50,14 +50,14 @@ public interface VotingBoothUI { * @param message a message to show the user on the UI device while waiting * @param callback a success return value of the wait (cancelling returns false) */ - public void askVoterToWaitForFinish (String message, FutureCallback callback); + public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); /** * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset * @param errorMessage message to show in UI device * @param callback returns interrupt */ - public void showErrorMessageAndHalt (String errorMessage, FutureCallback callback); + public void showErrorMessageAndHalt (UIElement errorMessage, FutureCallback callback); /** * show an error message and let user press his chosen button for continuation @@ -65,7 +65,7 @@ public interface VotingBoothUI { * @param buttonLabels labels for buttons to present to voter * @param callback the number of the selected button */ - public void showErrorMessageWithButtons (String errorMessage, String[] buttonLabels, + public void showErrorMessageWithButtons (UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback); } From e4a33af4d4dce07c7de88cca6cbd869fd626ce0f Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 18 Mar 2016 14:20:47 +0200 Subject: [PATCH 029/106] abort message --- .../src/main/java/Arithmetics/Arithmetic.java | 14 ++ .../src/main/java/Arithmetics/Fp.java | 53 ++++++ .../src/main/java/Arithmetics/Z.java | 29 ++++ .../main/java/Communication/MailHandler.java | 5 + .../java/Communication/MessageHandler.java | 1 + .../src/main/java/Communication/User.java | 2 +- .../DistributedKeyGeneration.java | 116 ++++++++----- .../DistributedKeyGenerationMailHandler.java | 7 +- .../DistributedKeyGenerationParty.java | 28 ++++ .../DistributedKeyGenerationUserImpl.java | 149 ++++++++--------- .../SecureDistributedKeyGeneration.java | 54 +++++-- ...reDistributedKeyGenerationMailHandler.java | 7 +- .../SecureDistributedKeyGenerationParty.java | 25 +++ ...ecureDistributedKeyGenerationUserImpl.java | 153 +++++++++--------- .../java/ShamirSecretSharing/Polynomial.java | 73 +++++---- .../ShamirSecretSharing/SecretSharing.java | 21 ++- .../java/JointFeldmanProtocol/DKGTest.java | 65 ++++---- .../DKGUserImplAbort.java | 63 ++++++++ .../src/test/java/SDKGTest.java | 67 ++++---- .../src/test/java/SDKGUserImplAbort.java | 62 +++++++ .../PolynomialTests/InterpolationTest.java | 19 ++- .../PolynomialTests/Utils.java | 9 ++ .../SecretSharingTest.java | 3 +- .../src/main/proto/meerkat/DKGMessages.proto | 5 +- 24 files changed, 705 insertions(+), 325 deletions(-) create mode 100644 destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java create mode 100644 destributed-key-generation/src/main/java/Arithmetics/Fp.java create mode 100644 destributed-key-generation/src/main/java/Arithmetics/Z.java create mode 100644 destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java create mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java create mode 100644 destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java create mode 100644 destributed-key-generation/src/test/java/SDKGUserImplAbort.java diff --git a/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java b/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java new file mode 100644 index 0000000..bd9920a --- /dev/null +++ b/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java @@ -0,0 +1,14 @@ +package Arithmetics; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public interface Arithmetic { + BigInteger add(T a,T b); + BigInteger sub(T a,T b); + BigInteger mul(T a,T b); + BigInteger div(T a,T b); + +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Fp.java b/destributed-key-generation/src/main/java/Arithmetics/Fp.java new file mode 100644 index 0000000..545dd8b --- /dev/null +++ b/destributed-key-generation/src/main/java/Arithmetics/Fp.java @@ -0,0 +1,53 @@ +package Arithmetics; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public class Fp implements Arithmetic { + public final BigInteger p; + + public Fp(BigInteger p) { + this.p = 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 a.multiply(b).mod(p); + } + + @Override + public BigInteger div(BigInteger a,BigInteger b){ + return mul(a,inv(b)); + } + + public BigInteger pow(BigInteger b,BigInteger e){ + if (e.compareTo(BigInteger.ZERO) < 0 ) { + return pow(inv(b), e.negate()); + } + BigInteger result = BigInteger.ONE; + while (e.compareTo(BigInteger.ZERO) > 0) { + if (e.testBit(0)) { + result = mul(result, b); + } + e = e.shiftRight(1); + b = mul(b, b); + } + return result; + } + + public BigInteger inv(BigInteger a){ + return pow(a,p.subtract(BigInteger.valueOf(2))); + } +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Z.java b/destributed-key-generation/src/main/java/Arithmetics/Z.java new file mode 100644 index 0000000..9523ead --- /dev/null +++ b/destributed-key-generation/src/main/java/Arithmetics/Z.java @@ -0,0 +1,29 @@ +package Arithmetics; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public class Z implements Arithmetic { + + @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); + } +} diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/Communication/MailHandler.java index 13bd347..fbb0522 100644 --- a/destributed-key-generation/src/main/java/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MailHandler.java @@ -42,6 +42,11 @@ public abstract class MailHandler { case ANSWER: messageHandler.handelAnswerMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST , message); + break; + case ABORT: + messageHandler.handelAbortMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; default: break; } diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/Communication/MessageHandler.java index a12a600..2d68be4 100644 --- a/destributed-key-generation/src/main/java/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MessageHandler.java @@ -11,4 +11,5 @@ public interface MessageHandler { void handelComplaintMessage(int sender, boolean isBroadcast, Message message); void handelDoneMessage(int sender, boolean isBroadcast, Message message); //will be remove void handelAnswerMessage(int sender, boolean isBroadcast, Message message); + void handelAbortMessage(int sender, boolean isBroadcast, Message message); } diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java index 3851b4d..2077d6e 100644 --- a/destributed-key-generation/src/main/java/Communication/User.java +++ b/destributed-key-generation/src/main/java/Communication/User.java @@ -18,7 +18,7 @@ public class User{ private final Network network; protected User(int ID, Network network, MailHandler mailHandler) { - this.mailbox = new ArrayBlockingQueue(2 * network.n * network.n); + this.mailbox = new ArrayBlockingQueue( network.n * network.n * network.n); this.ID = ID; this.mailHandler = mailHandler; this.receiverThread = new Thread(new Receiver()); diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java index b52a728..99feec6 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -1,10 +1,10 @@ package JointFeldmanProtocol; import Communication.User; -import ShamirSecretSharing.Polynomial; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import ShamirSecretSharing.Polynomial; import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages.*; +import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; @@ -14,20 +14,31 @@ import java.util.Random; import java.util.Set; /** - * Created by Tzlil on 2/5/2016. - * - * an implementation of a version of Pedersen's distributed key generation protocol + * Created by Tzlil on 3/14/2016. */ -public class DistributedKeyGeneration extends VerifiableSecretSharing{ - +public class DistributedKeyGeneration extends VerifiableSecretSharing { + public enum ComplainState{ + Non, Waiting,Disqualified,NonDisqualified + } protected final int id; - protected Polynomial.Point[] shares; + private DistributedKeyGenerationParty[] parties; + public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g , Group group, int id) { super(t, n, zi, random, q, g,group); this.id = id; - this.shares = null; + this.parties = new DistributedKeyGenerationParty[n]; + for (int i = 1; i <= n ; i++){ + this.parties[i - 1] = new DistributedKeyGenerationParty(i,n,t); + } + } + + protected void setParties(DistributedKeyGenerationParty[] parties){ + this.parties = parties; + } + protected DistributedKeyGenerationParty[] getParties(){ + return parties; } /** @@ -39,20 +50,20 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ } public void broadcastCommitments(User user, BigInteger[] commitments){ - CommitmentMessage commitmentMessage; + DKGMessages.CommitmentMessage commitmentMessage; for (int k = 0; k <= t ; k++){ - commitmentMessage = CommitmentMessage.newBuilder() + commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) .setK(k) .build(); - user.broadcast(Mail.Type.COMMITMENT, commitmentMessage); + user.broadcast(DKGMessages.Mail.Type.COMMITMENT, commitmentMessage); } } public void sendSecret(User user, int j){ ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); - user.send(j, Mail.Type.SECRET, - SecretMessage.newBuilder() + user.send(j, DKGMessages.Mail.Type.SECRET, + DKGMessages.SecretMessage.newBuilder() .setI(id) .setJ(j) .setSecret(secret) @@ -71,9 +82,9 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ } } - public boolean isValidSecret(int i,BigInteger[] commitments,int j){ - Polynomial.Point secret = shares[i - 1]; - return isValidSecret(secret,commitments,j); + public boolean isValidSecret(int i){ + DistributedKeyGenerationParty party = parties[i - 1]; + return isValidSecret(party.share,party.commitments,id); } public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ @@ -86,24 +97,29 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * Pj verifies all the shares he received (using isValidSecret) * if check fails for an index i, Pj broadcasts a complaint against Pi. */ - public void broadcastComplains(User user, BigInteger[][]commitmentsTable){ - ComplaintMessage complaint; + public void broadcastComplains(User user){ + DKGMessages.IDMessage complaint; for (int i = 1; i <= n ; i++ ){ - if(i != id) { - if (!isValidSecret(i,commitmentsTable[i - 1],id)) { - //message = new Message(Type.Complaint, j) - complaint = ComplaintMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(Mail.Type.COMPLAINT, complaint); - } + if(i != id && !parties[i - 1].aborted) { + sendComplain(user,i); } } } + protected void sendComplain(User user,int i){ + DKGMessages.IDMessage complaint; + if (!isValidSecret(i)) { + //message = new Message(Type.Complaint, j) + complaint = DKGMessages.IDMessage.newBuilder() + .setId(i) + .build(); + user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); + } + } + public void broadcastComplaintAnswer(User user, int j){ - user.broadcast(Mail.Type.ANSWER, SecretMessage.newBuilder() + user.broadcast(DKGMessages.Mail.Type.ANSWER, DKGMessages.SecretMessage.newBuilder() .setI(id) .setJ(j) .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) @@ -114,7 +130,8 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * stage3.1 according to the protocol * if more than t players complain against a player Pi he is disqualified. */ - public void answerAllComplainingPlayers(User user, DistributedKeyGenerationUserImpl.ComplainState[] complains){ + public void answerAllComplainingPlayers(User user){ + ComplainState[] complains = parties[id - 1].complaints; for (int i = 1; i <= n ; i++) { switch (complains[i - 1]) { case Waiting: @@ -126,20 +143,35 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ } } + protected boolean isPartyCompletedStage1(int i){ + if(parties[i - 1].aborted){ + if(parties[i - 1].share == null){ + return false; + } + for (int k = 0; k <= t ; k++){ + if(parties[i - 1].commitments[k] == null){ + return false; + } + } + } + return true; + } + /** * 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 calcQUAL(DistributedKeyGenerationUserImpl.ComplainState[][] complains){ + public Set calcQUAL(){ Set QUAL = new HashSet(); boolean nonDisqualified; int counter; - for (int i = 1; i <= complains.length; i++){ + for (int i = 1; i <= n; i++){ + ComplainState[] complains = parties[i - 1].complaints; nonDisqualified = true; counter = 0; - for (int j = 1; j <= complains[i - 1].length; j++){ - switch (complains[i - 1][j - 1]) { + for (int j = 1; j <= n; j++){ + switch (complains[j - 1]) { case Non: break; case NonDisqualified: @@ -150,7 +182,7 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ if(!nonDisqualified) break; } - if(nonDisqualified && counter <= t){ + if(nonDisqualified && counter <= t && isPartyCompletedStage1(i)){ QUAL.add(i); } } @@ -161,10 +193,10 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * stage4.1 according to the protocol * public value y is computed as y = multiplication of yi mod p for i in QUAL */ - public BigInteger calcY(BigInteger[] ys,Set QUAL){ + public BigInteger calcY(Set QUAL){ BigInteger y = group.zero(); for (int i : QUAL) { - y = group.add(y , ys[i - 1]); + y = group.add(y , parties[i - 1].commitments[0]); } return y; } @@ -173,12 +205,12 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * 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 BigInteger[] calcCommitments(BigInteger[][] commitmentsTable,Set QUAL){ + public BigInteger[] calcCommitments(Set QUAL){ BigInteger[] commitments = new BigInteger[t + 1]; Arrays.fill(commitments,group.zero()); for (int i : QUAL) { for (int k = 0; k <= t; k++){ - commitments[k] = group.add(commitments[k],commitmentsTable[i - 1][k]); + commitments[k] = group.add(commitments[k], parties[i - 1].commitments[k]); } } return commitments; @@ -188,10 +220,10 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ * stage4.3 according to the protocol * Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL */ - public Polynomial.Point calcShare(Polynomial.Point[] shares,Set QUAL){ + public Polynomial.Point calcShare(Set QUAL){ BigInteger xj = BigInteger.ZERO; for (int i : QUAL) { - xj = xj.add(shares[i - 1].y); + xj = xj.add(parties[i - 1].share.y); } return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } @@ -200,8 +232,4 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing{ return id; } - public void setShares(Polynomial.Point[] shares){ - this.shares = shares; - } - } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java index bc2c63e..fe141f2 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java @@ -27,14 +27,17 @@ public class DistributedKeyGenerationMailHandler extends MailHandler { message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); break; case COMPLAINT: - message = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); break; case DONE: - message = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); break; case ANSWER: message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; default: return null; } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java new file mode 100644 index 0000000..617ea08 --- /dev/null +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java @@ -0,0 +1,28 @@ +package JointFeldmanProtocol; + +import ShamirSecretSharing.Polynomial; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class DistributedKeyGenerationParty { + public final int id; + public Polynomial.Point share; + public BigInteger[] commitments; + public boolean doneFlag; + public DistributedKeyGeneration.ComplainState[] complaints; + public boolean aborted; + + public DistributedKeyGenerationParty(int id, int n, int t) { + this.id = id; + this.share = null; + this.doneFlag = false; + this.complaints = new DistributedKeyGeneration.ComplainState[n]; + Arrays.fill(this.complaints, DistributedKeyGeneration.ComplainState.Non); + this.commitments = new BigInteger[t + 1]; + this.aborted = false; + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java index 43958b2..f633258 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -13,14 +13,12 @@ import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; import java.util.Arrays; import java.util.Set; +import JointFeldmanProtocol.DistributedKeyGeneration.ComplainState; /** - * Created by Tzlil on 2/21/2016. + * Created by Tzlil on 3/14/2016. */ public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { - protected enum ComplainState{ - Non, Waiting,Disqualified,NonDisqualified - } protected final DistributedKeyGeneration dkg; @@ -31,12 +29,8 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio protected final int id; protected MessageHandler messageHandler; - protected final Polynomial.Point[] shares; - protected final BigInteger[][] commitmentsTable; - protected final boolean[] doneFlags; protected final User user; - protected final ComplainState[][] complaintsTable; - + protected final DistributedKeyGenerationParty[] parties; protected Set QUAL; // set of all non-disqualified parties protected BigInteger[] commitments; // public verification values protected Polynomial.Point share; // final share of the secrete @@ -57,14 +51,9 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio this.messageHandler = new MessageHandler(); mailHandler.setMessageHandler(this.messageHandler); this.user = network.connect(mailHandler); - this.shares = new Polynomial.Point[n]; - this.shares[id - 1] = dkg.getShare(id); - this.commitmentsTable = new BigInteger[n][t + 1]; - this.doneFlags = new boolean[n]; - this.complaintsTable = new ComplainState[n][n]; - for (int i = 0; i < n; i++){ - Arrays.fill(complaintsTable[i],ComplainState.Non); - } + this.parties = dkg.getParties(); + + this.parties[id - 1].share = dkg.getShare(id); this.QUAL = null; this.commitments = null; @@ -89,10 +78,15 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio * Pj broadcasts done message at the end of this stage */ protected void stage2(){ - dkg.setShares(shares); - dkg.broadcastComplains(user,commitmentsTable); + Polynomial.Point[] shares = new Polynomial.Point[n]; + BigInteger[][] commitmentsTable = new BigInteger[n][]; + for (int i = 0 ; i < n ; i++){ + shares[i] = parties[i].share; + commitmentsTable[i] = parties[i].commitments; + } + dkg.broadcastComplains(user); //broadcast done message after all complaints - DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); } @@ -104,13 +98,12 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio * set QUAL to be the set of non-disqualified players. */ protected void stage3(){ - - dkg.answerAllComplainingPlayers(user,complaintsTable[id - 1]); + dkg.answerAllComplainingPlayers(user); // wait until there is no complaint waiting for answer - for (int i = 0; i < complaintsTable.length; i++){ - for (int j = 0; j < complaintsTable[i].length; j++){ - while (complaintsTable[i][j].equals(ComplainState.Waiting)){ + for (int i = 0; i < n; i++){ + for (int j = 0; j < n; j++){ + while (parties[i].complaints[j].equals(ComplainState.Waiting) && !parties[i].aborted){ try { Thread.sleep(300); } catch (InterruptedException e) { @@ -119,7 +112,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio } } } - this.QUAL = dkg.calcQUAL(complaintsTable); + this.QUAL = dkg.calcQUAL(); } /** @@ -129,34 +122,51 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio * 3. Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL */ protected void stage4(){ - BigInteger[] ys = new BigInteger[n]; - for (int i = 0; i < n; i++){ - ys[i] = commitmentsTable[i][0]; + this.y = dkg.calcY(QUAL); + this.commitments = dkg.calcCommitments(QUAL); + this.share = dkg.calcShare(QUAL); + } + + protected void endOfStage1(){ + for (int i = 0 ; i < n ; i++){ + while (parties[i].share == null && !parties[i].aborted){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + + for (int i = 0 ; i < n ; i++){ + for (int k = 0 ; k <= t ; k++) { + while (parties[i].commitments[k] == null && !parties[i].aborted) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } } - this.y = dkg.calcY(ys,QUAL); - this.commitments = dkg.calcCommitments(commitmentsTable,QUAL); - this.share = dkg.calcShare(shares,QUAL); } @Override public void run() { user.getReceiverThread().start(); stage1(); - while (messageHandler.secretsCounter != n - 1 || messageHandler.commitmentsCounter != n * (t + 1)){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } + endOfStage1(); stage2(); - while (messageHandler.doneCounter != n){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing + for (int i = 0 ; i < n ; i++){ + while (!parties[i].doneFlag && !parties[i].aborted){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } } } + stage3(); stage4(); user.getReceiverThread().interrupt(); @@ -208,49 +218,37 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio } protected class MessageHandler implements Communication.MessageHandler{ - - public int doneCounter; - public int commitmentsCounter; - public int secretsCounter; - - public MessageHandler() { - this.doneCounter = 0; - this.secretsCounter = 0; - this.commitmentsCounter = 0; - } - - protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKGMessages.ComplaintMessage complaintMessage){ + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKGMessages.IDMessage complaintMessage){ int i = sender; int j = complaintMessage.getId(); - return isBroadcast && complaintsTable[i - 1][j - 1].equals( ComplainState.Non); + return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplainState.Non); } @Override public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.ComplaintMessage complaintMessage = (DKGMessages.ComplaintMessage)message; + DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ int i = sender; int j = complaintMessage.getId(); - complaintsTable[i - 1][j - 1] = ComplainState.Waiting; + parties[i - 1].complaints[j - 1] = ComplainState.Waiting; } } protected boolean isValidDoneMessage(int sender, boolean isBroadcast){ - return isBroadcast && !doneFlags[sender - 1]; + return isBroadcast && !parties[sender - 1].doneFlag; } @Override public void handelDoneMessage(int sender, boolean isBroadcast,Message message) { if(isValidDoneMessage(sender,isBroadcast)) { - doneFlags[sender - 1] = true; - doneCounter++; + parties[sender - 1].doneFlag = true; } } protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage){ int i = sender - 1; int k = commitmentMessage.getK(); - return isBroadcast && commitmentsTable[i][k] == null; + return isBroadcast && parties[i].commitments[k] == null; } @Override @@ -259,8 +257,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ int i = sender - 1; int k = commitmentMessage.getK(); - commitmentsTable[i][k] = extractCommitment(commitmentMessage); - commitmentsCounter++; + parties[i].commitments[k] = extractCommitment(commitmentMessage); } } @@ -270,7 +267,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio if(sender != i || isBroadcast) return false; else - return shares[i - 1] == null && j == id; + return parties[i - 1].share == null && j == id; } @@ -279,9 +276,8 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { int i = secretMessage.getI(); - Polynomial.Point secret = extractSecret(i,secretMessage.getSecret()); - shares[i - 1] = secret; - secretsCounter++; + Polynomial.Point secret = extractSecret(id,secretMessage.getSecret()); + parties[i - 1].share = secret; } } @@ -291,7 +287,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio if(sender != i || !isBroadcast) return false; else - return j >= 1 && j <= n && complaintsTable[i - 1][j - 1].equals(ComplainState.Waiting); + return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(ComplainState.Waiting); } @Override @@ -300,14 +296,19 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { int i = secretMessage.getI(); int j = secretMessage.getJ(); - Polynomial.Point secret = extractSecret(i,secretMessage.getSecret()); - if (dkg.isValidSecret(secret, commitmentsTable[i - 1], j)) - complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + Polynomial.Point secret = extractSecret(j,secretMessage.getSecret()); + if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) + parties[i - 1].complaints[j - 1] = ComplainState.NonDisqualified; else - complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + parties[i - 1].complaints[j - 1] = ComplainState.Disqualified; } } + @Override + public void handelAbortMessage(int sender, boolean isBroadcast, Message message) { + parties[sender - 1].aborted = true; + } + public Polynomial.Point extractSecret(int i, ByteString secret){ BigInteger x = BigInteger.valueOf(i); BigInteger y = new BigInteger(secret.toByteArray()); diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java index 05e892e..4a05125 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java @@ -12,13 +12,13 @@ import java.math.BigInteger; import java.util.Random; /** - * Created by Tzlil on 2/17/2016. + * Created by Tzlil on 3/16/2016. */ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { private VerifiableSecretSharing verifiableSecretSharing; private final BigInteger h; - private Polynomial.Point[] sharesT; + private SecureDistributedKeyGenerationParty[] parties; public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g , BigInteger h, Group group, int id) { @@ -26,10 +26,34 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { this.h = h; BigInteger r = new BigInteger(q.bitLength(),random).mod(q); this.verifiableSecretSharing = new VerifiableSecretSharing(t,n,r,random,q,h,group); + this.parties = new SecureDistributedKeyGenerationParty[n]; + for (int i = 1; i <= n ; i++){ + this.parties[i - 1] = new SecureDistributedKeyGenerationParty(i,n,t); + } + setParties(parties); + } + + protected SecureDistributedKeyGenerationParty[] getParties(){ + return parties; } @Override - public void sendSecret(User user,int j) { + protected boolean isPartyCompletedStage1(int i){ + if(parties[i - 1].aborted){ + if(parties[i - 1].share == null){ + return false; + } + for (int k = 0; k <= t ; k++){ + if(parties[i - 1].verifiableValues[k] == null){ + return false; + } + } + } + return true; + } + + @Override + public void sendSecret(User user, int j) { Polynomial.Point secret = getShare(j); Polynomial.Point secretT = verifiableSecretSharing.getShare(j); DKGMessages.DoubleSecretMessage doubleSecretMessage = doubleSecretMessage(id,j,secret,secretT); @@ -37,10 +61,9 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { } @Override - public boolean isValidSecret(int i, BigInteger[] commitments, int j){ - Polynomial.Point secret = shares[i - 1]; - Polynomial.Point secretT = sharesT[i - 1]; - return isValidSecret(secret,secretT,commitments, j); + public boolean isValidSecret(int i){ + SecureDistributedKeyGenerationParty party = parties[i - 1]; + return isValidSecret(party.share,party.shareT,party.verifiableValues, id); } public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int j){ @@ -49,7 +72,6 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { return exp.equals(v); } - public void broadcastComplaint(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); @@ -64,14 +86,16 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { * stage4.3 according to the protocol * if check fails for index i, Pj */ - public void broadcastComplaints(User user, BigInteger[][] commitmentsTable, boolean stage4){ + public void broadcastComplaints(User user, boolean stage4){ if(!stage4){ - broadcastComplains(user,commitmentsTable); + super.broadcastComplains(user); }else{ + SecureDistributedKeyGenerationParty party; for (int i = 1; i <= n ; i++ ){ - if(i != id) { - if (!isValidSecret(shares[i - 1],commitmentsTable[i - 1],id)) { - broadcastComplaint(user,shares[i - 1],sharesT[i - 1],i); + party = parties[i - 1]; + if(i != id && !party.aborted) { + if (!super.isValidSecret(party.share,party.commitments,id)) { + broadcastComplaint(user,party.share,party.shareT,i); } } } @@ -104,8 +128,4 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { ,verifiableSecretSharing.getShare(j)); user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); } - - public void setSharesT(Polynomial.Point[] sharesT) { - this.sharesT = sharesT; - } } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java index 2f60c6d..bad5d07 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java @@ -31,16 +31,19 @@ public class SecureDistributedKeyGenerationMailHandler extends MailHandler { break; case COMPLAINT: if(isStage4) - message = DKGMessages.ComplaintMessage.parseFrom(mail.getMessage()); + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); else message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); break; case DONE: - message = DKGMessages.DoneMessage.parseFrom(mail.getMessage()); + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); break; case ANSWER: message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; default: return null; } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java new file mode 100644 index 0000000..3d933a9 --- /dev/null +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java @@ -0,0 +1,25 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import JointFeldmanProtocol.DistributedKeyGenerationParty; +import ShamirSecretSharing.Polynomial; + +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by Tzlil on 3/16/2016. + */ +public class SecureDistributedKeyGenerationParty extends DistributedKeyGenerationParty { + + + public Polynomial.Point shareT; + public BigInteger[] verifiableValues; + public Set restoreSharesSet; + public SecureDistributedKeyGenerationParty(int id, int n, int t) { + super(id, n, t); + this.shareT = null; + this.verifiableValues = new BigInteger[t + 1]; + this.restoreSharesSet = new HashSet(); + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java index e8fcf9d..778a5d2 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java @@ -1,6 +1,9 @@ package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; +import Arithmetics.Arithmetic; +import Arithmetics.Fp; import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGeneration; import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; @@ -8,28 +11,23 @@ import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; import java.math.BigInteger; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Set; /** - * Created by Tzlil on 2/22/2016. + * Created by Tzlil on 3/16/2016. */ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { private final SecureDistributedKeyGeneration sdkg; - private final Polynomial.Point[] sharesT; - private final BigInteger[][] verificationValuesTable; - private final Hashtable> ysRestoreShares; + private SecureDistributedKeyGenerationParty[] parties; + private Arithmetic arithmetic; public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); this.sdkg = sdkg; - this.sharesT = new Polynomial.Point[n]; - this.verificationValuesTable = new BigInteger[n][t + 1]; - this.ysRestoreShares = new Hashtable>(); this.messageHandler = new MessageHandler(); this.user.setMessageHandler(this.messageHandler); + this.parties = sdkg.getParties(); + this.arithmetic = new Fp(sdkg.getQ()); } /** @@ -43,6 +41,17 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera sdkg.sendSecrets(user); } + @Override + protected void endOfStage1(){ + super.endOfStage1(); + BigInteger[] 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 @@ -51,11 +60,10 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera */ @Override protected void stage2(){ - sdkg.setShares(shares); - sdkg.setSharesT(sharesT); - sdkg.broadcastComplains(user,verificationValuesTable); + sdkg.broadcastComplains(user); //broadcast done message after all complaints - DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + isVerificationValue = false; user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); } @@ -64,7 +72,7 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera //wait for receive all commitments from all i in QUAL for (int i:QUAL) { for(int k = 0; k <= t; k++) { - while (commitmentsTable[i - 1][k] == null) { + while (parties[i - 1].commitments[k] == null && !parties[i - 1].aborted) { try { Thread.sleep(300); } catch (InterruptedException e) { @@ -73,13 +81,13 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera } } } - sdkg.broadcastComplaints(user,commitmentsTable,true); + sdkg.broadcastComplaints(user,true); //broadcast done message after all complaints - DKGMessages.DoneMessage doneMessage = DKGMessages.DoneMessage.newBuilder().build(); + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); for (int i:QUAL) { - while (doneFlags[i - 1]) { + while (parties[i - 1].doneFlag && !parties[i - 1].aborted) { try { Thread.sleep(300); } catch (InterruptedException e) { @@ -87,11 +95,40 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera } } } - BigInteger secret; - for (Integer i: ysRestoreShares.keySet()) { + + int counter = 0; + for (int i:QUAL) { + if(parties[i - 1].aborted){ + counter++; + sdkg.broadcastAnswer(user, parties[i - 1].share, parties[i - 1].shareT, i); + } + } + for (int i:QUAL) { + if(parties[i - 1].aborted){ + while (parties[i - 1].restoreSharesSet.size() < n - counter) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + for (int i = 0; i < n ; i++) { + if(parties[i].restoreSharesSet.isEmpty()){ + continue; + } try { - secret = SecretSharing.restoreSecret((Polynomial.Point[])ysRestoreShares.get(i).toArray()); - //ToDo use restored secret... + Polynomial.Point[] shares = new Polynomial.Point[parties[i].restoreSharesSet.size()]; + parties[i].restoreSharesSet.toArray(shares); + Polynomial polynomial = SecretSharing.restorePolynomial(shares,arithmetic); + BigInteger[] coefficients = polynomial.getCoefficients(); + for (int k = 0 ; k <= t; k++){ + parties[i].commitments[k] = group.multiply(g,coefficients[k]); + } + parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); + } catch (Exception e) { // } @@ -106,37 +143,9 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera super.stage4(); } boolean isStage4 = false; + boolean isVerificationValue = true; private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ - final int NumberOfCommitmentsInStage1 = n * (t + 1); - - @Override - protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKGMessages.CommitmentMessage commitmentMessage) { - if(commitmentsCounter < NumberOfCommitmentsInStage1) { - int i = sender - 1; - int k = commitmentMessage.getK(); - return isBroadcast && verificationValuesTable[i][k] == null; - }else { - return super.isValidCommitmentMessage(sender, isBroadcast, commitmentMessage); - } - } - - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.CommitmentMessage commitmentMessage = ( DKGMessages.CommitmentMessage)message; - if(commitmentsCounter < NumberOfCommitmentsInStage1) { - if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)) { - int i = sender - 1; - int k = commitmentMessage.getK(); - verificationValuesTable[i][k] = extractCommitment(commitmentMessage); - commitmentsCounter++; - } - } - else{ - super.handelCommitmentMessage(sender,isBroadcast,commitmentMessage); - } - } - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() .setI(doubleSecretMessage.getI()) @@ -152,11 +161,8 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); - Polynomial.Point secret = extractSecret(i, doubleSecretMessage.getSecret()); - Polynomial.Point secretT = extractSecret(i, doubleSecretMessage.getSecretT()); - shares[i - 1] = secret; - sharesT[i - 1] = secretT; - secretsCounter++; + parties[i - 1].share = extractSecret(id, doubleSecretMessage.getSecret()); + parties[i - 1].shareT = extractSecret(id, doubleSecretMessage.getSecretT()); } } protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { @@ -170,7 +176,7 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera }else{ int i = doubleSecretMessage.getI(); int j = doubleSecretMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j)&& ysRestoreShares.containsKey(i); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); } } @@ -180,38 +186,36 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); int j = doubleSecretMessage.getJ(); - Polynomial.Point secret = extractSecret(i, doubleSecretMessage.getSecret()); - Polynomial.Point secretT = extractSecret(i, doubleSecretMessage.getSecretT()); + Polynomial.Point secret = extractSecret(j, doubleSecretMessage.getSecret()); + Polynomial.Point secretT = extractSecret(j, doubleSecretMessage.getSecretT()); if (!isStage4) { - if (sdkg.isValidSecret(secret, secretT, verificationValuesTable[j - 1], i)) { - complaintsTable[i - 1][j - 1] = ComplainState.NonDisqualified; + if (sdkg.isValidSecret(secret, secretT, parties[j - 1].verifiableValues, i)) { + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplainState.NonDisqualified; } else { - complaintsTable[i - 1][j - 1] = ComplainState.Disqualified; + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplainState.Disqualified; } } else { - if (ysRestoreShares.get(i).add(secret) && sender != id) { - sdkg.broadcastAnswer(user, secret, secretT, i); - } + parties[i - 1].restoreSharesSet.add(secret); } } } @Override protected boolean isValidDoneMessage(int sender, boolean isBroadcast) { - if(doneCounter < n) { + if(!isStage4) { return super.isValidDoneMessage(sender, isBroadcast); }else{ - return isBroadcast && doneFlags[sender - 1]; + return isBroadcast && parties[sender - 1].doneFlag; } } @Override public void handelDoneMessage(int sender, boolean isBroadcast, Message message) { - if(doneCounter < n) + if(!isStage4) super.handelDoneMessage(sender, isBroadcast, message); else{ if(isValidDoneMessage(sender,isBroadcast)) { - doneFlags[sender - 1] = false; + parties[sender - 1].doneFlag = false; } } } @@ -220,9 +224,11 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera DKGMessages.DoubleSecretMessage ysComplaintMessage){ int i = ysComplaintMessage.getI(); int j = ysComplaintMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j)&&!ysRestoreShares.containsKey(i); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); } + + @Override public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { if(!isStage4) { @@ -234,10 +240,9 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera int j = ysComplaintMessage.getJ(); Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); - if (sdkg.isValidSecret(secret, secretT, verificationValuesTable[i - 1], j) - && !sdkg.isValidSecret(secret, commitmentsTable[i - 1], j)) { - ysRestoreShares.put(i, new HashSet()); - ysRestoreShares.get(i).add(secret); + if (sdkg.isValidSecret(secret, secretT, parties[i - 1].commitments, j) + && !sdkg.isValidSecret(secret,parties[i - 1].commitments, j)) { + parties[i - 1].restoreSharesSet.add(secret); sdkg.broadcastAnswer(user, secret, secretT, i); } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index cf8719f..119cf61 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -1,18 +1,19 @@ package ShamirSecretSharing; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; -import org.bouncycastle.util.Arrays; +import Arithmetics.Arithmetic; +import Arithmetics.Z; + import java.math.BigInteger; +import java.util.Arrays; /** * Created by Tzlil on 1/27/2016. */ public class Polynomial implements Comparable { - public static final Polynomial ZERO = new Polynomial(new BigInteger[]{BigInteger.ZERO}); // neutral for add - public static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); // neutral for mul + public static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); private final int degree; private final BigInteger[] coefficients; + private final Arithmetic arithmetic; /** * constructor @@ -20,12 +21,17 @@ public class Polynomial implements Comparable { * degree set as max index such that coefficients[degree] not equals zero */ public Polynomial(BigInteger[] coefficients) { + this(coefficients,new Z()); + } + + public Polynomial(BigInteger[] coefficients,Arithmetic arithmetic) { int d = coefficients.length - 1; while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){ d--; } this.degree = d; this.coefficients = coefficients; + this.arithmetic = arithmetic; } @@ -60,7 +66,7 @@ public class Polynomial implements Comparable { BigInteger result = BigInteger.ZERO; BigInteger power = BigInteger.ONE; for(int i = 0 ; i <= degree ; i++){ - result = result.add(coefficients[i].multiply(power)); + result = arithmetic.add(result,arithmetic.mul(coefficients[i],power)); power = power.multiply(x); } return result; @@ -70,19 +76,18 @@ public class Polynomial implements Comparable { * @param points * @return polynomial of minimal degree which goes through all points */ - public static Polynomial interpolation(Point[] points) throws Exception { + public static Polynomial interpolation(Point[] points, Arithmetic arithmetic) throws Exception { LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points); - // product = product of l[i].divisor BigInteger product = BigInteger.ONE; for (int i = 0; i < l.length;i++){ - product = product.multiply(l[i].divisor); + 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] = product.divide(l[i].divisor); + factors[i] = arithmetic.div(product,l[i].divisor); } int degree = l[0].polynomial.degree; @@ -92,11 +97,13 @@ public class Polynomial implements Comparable { for (int j = 0; j < coefficients.length;j++){ coefficients[j] = BigInteger.ZERO; for (int i = 0; i < l.length; i++){ - coefficients[j] = coefficients[j].add(l[i].image.multiply(factors[i]).multiply(l[i].polynomial.coefficients[j])); + 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] = coefficients[j].divide(product); + coefficients[j] = arithmetic.div(coefficients[j],product); } - return new Polynomial(coefficients); + return new Polynomial(coefficients,arithmetic); } /** @@ -116,14 +123,14 @@ public class Polynomial implements Comparable { BigInteger[] coefficients = bigger.getCoefficients(); for (int i = 0; i <= smaller.degree ; i++){ - coefficients[i] = smaller.coefficients[i].add(bigger.coefficients[i]); + coefficients[i] = arithmetic.add(smaller.coefficients[i],bigger.coefficients[i]); } - return new Polynomial(coefficients); + return new Polynomial(coefficients,other.arithmetic); } /** * @param constant - * @return new ShamirSecretSharing.PolynomialTests of degree this.degree s.t for all x in Z + * @return new Polynomial of degree this.degree s.t for all x in Z * new.image(x) = constant * this.image(x) */ public Polynomial mul(BigInteger constant){ @@ -131,27 +138,27 @@ public class Polynomial implements Comparable { BigInteger[] coefficients = this.getCoefficients(); for (int i = 0; i <= this.degree ; i++){ - coefficients[i] = constant.multiply(coefficients[i]); + coefficients[i] = arithmetic.mul(constant,coefficients[i]); } - return new Polynomial(coefficients); + return new Polynomial(coefficients,arithmetic); } /** * @param other - * @return new ShamirSecretSharing.PolynomialTests of degree this degree + other degree + 1 s.t for all x in Z + * @return new Polynomial of degree this degree + other degree + 1 s.t for all x in Z * new.image(x) = this.image(x) * other.image(x) */ public Polynomial mul(Polynomial other){ BigInteger[] coefficients = new BigInteger[this.degree + other.degree + 1]; - java.util.Arrays.fill(coefficients,BigInteger.ZERO); + Arrays.fill(coefficients,BigInteger.ZERO); for (int i = 0; i <= this.degree ; i++){ for (int j = 0; j <= other.degree; j++){ - coefficients[i+j] = coefficients[i+j].add(this.coefficients[i].multiply(other.coefficients[j])); + coefficients[i+j] = arithmetic.add(coefficients[i+j],arithmetic.mul(this.coefficients[i],other.coefficients[j])); } } - return new Polynomial(coefficients); + return new Polynomial(coefficients,arithmetic); } @@ -159,7 +166,7 @@ public class Polynomial implements Comparable { * @return copy of coefficients */ public BigInteger[] getCoefficients() { - return Arrays.clone(coefficients); + return Arrays.copyOf(coefficients,coefficients.length); } /** getter @@ -187,18 +194,6 @@ public class Polynomial implements Comparable { this.y = polynomial.image(x); } - /** - * constructor - * @param x - * @param p - * @param polynomial y = polynomial.image(x) % q - * - */ - public Point(BigInteger x, Polynomial polynomial,BigInteger p) { - this.x = x; - this.y = polynomial.image(x); - } - /** * constructor * @param x @@ -208,6 +203,14 @@ public class Polynomial implements Comparable { 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); + } } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 7b6133f..cdd631d 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -1,9 +1,6 @@ package ShamirSecretSharing; - -import Communication.Network; -import Communication.User; -import meerkat.protobuf.DKGMessages; +import Arithmetics.Arithmetic; import java.math.BigInteger; import java.util.Random; @@ -58,7 +55,7 @@ public class SecretSharing{ */ public Polynomial.Point getShare(int i){ assert (i > 0 && i <= n); - return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); + return new Polynomial.Point(BigInteger.valueOf(i), polynomial); } /** @@ -66,9 +63,17 @@ public class SecretSharing{ * * @return image of interpolation(shares) at x = 0 */ - public static BigInteger restoreSecret(Polynomial.Point[] shares) throws Exception { - Polynomial polynomial = Polynomial.interpolation(shares); - return polynomial.image(BigInteger.ZERO); + public static BigInteger restoreSecret(Polynomial.Point[] shares,Arithmetic arithmetic) throws Exception { + return restorePolynomial(shares,arithmetic).image(BigInteger.ZERO); + } + + /** + * @param shares - subset of the original shares + * + * @return interpolation(shares) + */ + public static Polynomial restorePolynomial(Polynomial.Point[] shares,Arithmetic arithmetic) throws Exception { + return Polynomial.interpolation(shares,arithmetic); } /** diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index 066daff..b74f258 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -1,5 +1,6 @@ package JointFeldmanProtocol; +import Arithmetics.Z; import Communication.Network; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; @@ -11,7 +12,7 @@ import org.junit.Before; import org.junit.Test; import java.math.BigInteger; -import java.util.Random; +import java.util.*; /** * Created by Tzlil on 2/9/2016. @@ -25,6 +26,7 @@ public class DKGTest { BigInteger p = BigInteger.valueOf(2903); BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); BigInteger[] secrets; + Set QUAL = new HashSet(); @Before public void settings(){ Zpstar zpstar = new Zpstar(p); @@ -37,18 +39,28 @@ public class DKGTest { threadsArrays = new Thread[tests][n]; secrets = new BigInteger[tests]; DistributedKeyGeneration dkg; + int abortedStage = 2; for (int test = 0; test < tests; test++) { do { g = zpstar.sample(random); } while (!g.equals(ZERO) && !zpstar.multiply(g, q).equals(ZERO));// sample from QRZp* secrets[test] = BigInteger.ZERO; Network network = new Network(n); - for (int i = 0; i < n; i++) { + for (int i = 1; i <= n; i++) { BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); - secrets[test] = secrets[test].add(secret).mod(q); - dkg = new DistributedKeyGeneration(t,n,secret,random,q,g,zpstar,i + 1); - dkgsArrays[test][i] = new DistributedKeyGenerationUserImpl(dkg,network); - threadsArrays[test][i] = new Thread(dkgsArrays[test][i]); + dkg = new DistributedKeyGeneration(t,n,secret,random,q,g,zpstar,i); + + if(i == n) { + dkgsArrays[test][i - 1] = new DKGUserImplAbort(dkg, network, abortedStage); + } + else { + dkgsArrays[test][i - 1] = new DistributedKeyGenerationUserImpl(dkg, network); + QUAL.add(i); + } + if (abortedStage > 1 || (abortedStage == 1 && i != n)){ + secrets[test] = secrets[test].add(secret).mod(q); + } + threadsArrays[test][i - 1] = new Thread(dkgsArrays[test][i - 1]); } } } @@ -67,39 +79,32 @@ public class DKGTest { BigInteger g = dkgs[0].getGenerator(); // got the right public value - BigInteger publicValue = dkgs[0].getPublicValue(); - assert(zpstar.multiply(g,secret).equals(publicValue)); - - // assert all players agreed on the same public value - for (int i = 0; i < dkgs.length - 1 ; i++){ - assert (dkgs[i].getPublicValue().equals(dkgs[i+1].getPublicValue())); + BigInteger publicValue = zpstar.multiply(g,secret); + for (int i: QUAL){ + if(i != n) + assert (dkgs[i - 1].getPublicValue().equals(publicValue)); } // assert valid verification values BigInteger expected,verification; - for (int j = 1; j <= dkgs.length ; j++){ - expected = zpstar.multiply(g, dkgs[j - 1].getShare().y); - verification = VerifiableSecretSharing.verify(j, dkgs[j - 1].getCommitments(),zpstar); + for (int i: QUAL){ + expected = zpstar.multiply(g, dkgs[i - 1].getShare().y); + verification = VerifiableSecretSharing.verify(i, dkgs[i - 1].getCommitments(),zpstar); assert (expected.equals(verification)); } - // restore the secret from t + 1 random shares - Polynomial.Point[] shares = new Polynomial.Point[t + 1]; - for (int i = 0 ; i < shares.length; i++){ - shares[i] = dkgs[i].getShare(); + // restore the secret from shares + ArrayList sharesList = new ArrayList(); + Polynomial.Point[] shares = new Polynomial.Point[QUAL.size()]; + for(int i : QUAL){ + sharesList.add(dkgs[i - 1].getShare()); } - //List indexes = new ArrayList(n); - //for (int i = 1 ; i <= n; i ++){ - // indexes.add(i); - //} - //Random random = new Random(); - //int index; - //for (int i = 0 ; i < shares.length ; i++){ - // index = indexes.remove(random.nextInt(indexes.size())); - // shares[i] = dkgs[index - 1].getShare(); - //} - BigInteger calculatedSecret = SecretSharing.restoreSecret(shares).mod(q); + for (int i = 0; i < shares.length; i ++){ + shares[i] = sharesList.get(i); + } + + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,new Z()).mod(q); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java new file mode 100644 index 0000000..39f211a --- /dev/null +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java @@ -0,0 +1,63 @@ +package JointFeldmanProtocol; + +import Communication.Network; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class DKGUserImplAbort extends DistributedKeyGenerationUserImpl { + + final int abortStage; + int stage; + public DKGUserImplAbort(DistributedKeyGeneration dkg, Network network, int abortStage) { + super(dkg, network); + this.abortStage = abortStage;// 1 - 2 + this.stage = 1; + } + + + private void sendAbort(){ + user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/SDKGTest.java b/destributed-key-generation/src/test/java/SDKGTest.java index e295099..5866063 100644 --- a/destributed-key-generation/src/test/java/SDKGTest.java +++ b/destributed-key-generation/src/test/java/SDKGTest.java @@ -1,3 +1,4 @@ +import Arithmetics.Z; import Communication.Network; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; @@ -11,7 +12,10 @@ import org.junit.Before; 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 2/23/2016. @@ -24,6 +28,9 @@ public class SDKGTest { BigInteger p = BigInteger.valueOf(2903); BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); BigInteger[] secrets; + + Set QUAL = new HashSet(); + @Before public void settings(){ Zpstar zpstar = new Zpstar(p); @@ -43,16 +50,26 @@ public class SDKGTest { h = zpstar.multiply(g,BigInteger.valueOf(2)); secrets[test] = BigInteger.ZERO; Network network = new Network(n); - for (int i = 0; i < n; i++) { + int abortedStage = 2; + for (int i = 1; i <= n; i++) { BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); - secrets[test] = secrets[test].add(secret).mod(q); - sdkg = new SecureDistributedKeyGeneration(t,n,secret,random,q,g,h,zpstar,i + 1); - sdkgsArrays[test][i] = new SecureDistributedKeyGenerationUserImpl(sdkg,network); - threadsArrays[test][i] = new Thread(sdkgsArrays[test][i]); + sdkg = new SecureDistributedKeyGeneration(t,n,secret,random,q,g,h,zpstar,i); + if(i == n) { + sdkgsArrays[test][i - 1] = new SDKGUserImplAbort(sdkg, network, abortedStage); + } + else { + sdkgsArrays[test][i - 1] = new SecureDistributedKeyGenerationUserImpl(sdkg, network); + QUAL.add(i); + } + if (abortedStage > 1 || (abortedStage == 1 && i != n)){ + secrets[test] = secrets[test].add(secret).mod(q); + } + threadsArrays[test][i - 1] = new Thread(sdkgsArrays[test][i - 1]); } } } + public void oneTest(Thread[] threads, DistributedKeyGenerationUser[] dkgs,BigInteger secret) throws Exception { for (int i = 0; i < threads.length ; i++){ threads[i].start(); @@ -67,39 +84,31 @@ public class SDKGTest { BigInteger g = dkgs[0].getGenerator(); // got the right public value - BigInteger publicValue = dkgs[0].getPublicValue(); - assert(zpstar.multiply(g,secret).equals(publicValue)); - - // assert all players agreed on the same public value - for (int i = 0; i < dkgs.length - 1 ; i++){ - assert (dkgs[i].getPublicValue().equals(dkgs[i+1].getPublicValue())); + BigInteger publicValue = zpstar.multiply(g,secret); + for (int i: QUAL){ + assert (dkgs[i - 1].getPublicValue().equals(publicValue)); } // assert valid verification values BigInteger expected,verification; - for (int j = 1; j <= dkgs.length ; j++){ - expected = zpstar.multiply(g, dkgs[j - 1].getShare().y); - verification = VerifiableSecretSharing.verify(j, dkgs[j - 1].getCommitments(),zpstar); + for (int i: QUAL){ + expected = zpstar.multiply(g, dkgs[i - 1].getShare().y); + verification = VerifiableSecretSharing.verify(i, dkgs[i - 1].getCommitments(),zpstar); assert (expected.equals(verification)); } - // restore the secret from t + 1 random shares - Polynomial.Point[] shares = new Polynomial.Point[t + 1]; - for (int i = 0 ; i < shares.length; i++){ - shares[i] = dkgs[i].getShare(); + // restore the secret from shares + ArrayList sharesList = new ArrayList(); + Polynomial.Point[] shares = new Polynomial.Point[QUAL.size()]; + for(int i : QUAL){ + sharesList.add(dkgs[i - 1].getShare()); } - //List indexes = new ArrayList(n); - //for (int i = 1 ; i <= n; i ++){ - // indexes.add(i); - //} - //Random random = new Random(); - //int index; - //for (int i = 0 ; i < shares.length ; i++){ - // index = indexes.remove(random.nextInt(indexes.size())); - // shares[i] = dkgs[index - 1].getShare(); - //} - BigInteger calculatedSecret = SecretSharing.restoreSecret(shares).mod(q); + for (int i = 0; i < shares.length; i ++){ + shares[i] = sharesList.get(i); + } + + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,new Z()).mod(q); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/SDKGUserImplAbort.java new file mode 100644 index 0000000..bc30eb5 --- /dev/null +++ b/destributed-key-generation/src/test/java/SDKGUserImplAbort.java @@ -0,0 +1,62 @@ +import Communication.Network; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { + + final int abortStage; + int stage; + public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Network network, int abortStage) { + super(sdkg, network); + this.abortStage = abortStage;// 1 - 4 + this.stage = 1; + } + + private void sendAbort(){ + user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index b1539cc..2f5ba39 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -1,5 +1,8 @@ package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Arithmetics.Z; import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; @@ -19,35 +22,39 @@ public class InterpolationTest { int bits = 128; Random random; Polynomial.Point[][] pointsArrays; + Arithmetic arithmetic; + BigInteger p = BigInteger.valueOf(2903); + @Before public void settings(){ random = new Random(); polynomials = new Polynomial[tests]; pointsArrays = new Polynomial.Point[tests][]; for (int i = 0; i < polynomials.length; i++){ - polynomials[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + polynomials[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); pointsArrays[i] = randomPoints(polynomials[i]); } + arithmetic = new Fp(p); } - public Polynomial.Point[] randomPoints(Polynomial p){ - Polynomial.Point[] points = new Polynomial.Point[p.getDegree() + 1]; + public Polynomial.Point[] randomPoints(Polynomial polynomial){ + Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1]; BigInteger x; Set set = new HashSet(); for (int i = 0; i < points.length; i++){ - x = new BigInteger(bits,random); + x = new BigInteger(bits,random).mod(p); if(set.contains(x)){ i--; continue; } set.add(x); - points[i] = new Polynomial.Point(x,p); + points[i] = new Polynomial.Point(x,polynomial); } return points; } public void oneTest(Polynomial p, Polynomial.Point[] points) throws Exception { - Polynomial interpolation = Polynomial.interpolation(points); + Polynomial interpolation = Polynomial.interpolation(points,arithmetic); assert (p.compareTo(interpolation) == 0); } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java index 47dca28..8ec057a 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java @@ -1,5 +1,6 @@ package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Fp; import ShamirSecretSharing.Polynomial; import java.math.BigInteger; @@ -18,4 +19,12 @@ public class Utils { } return new Polynomial(coefficients); } + + public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) { + BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random).getCoefficients(); + for (int i = 0; i Date: Mon, 21 Mar 2016 20:32:57 +0200 Subject: [PATCH 030/106] Local Client for testing (without subscription yet) Partial implementation of subscriptions. Some bug fixes. --- .../SimpleBulletinBoardClient.java | 35 ++ .../SingleServerBulletinBoardClient.java | 51 +- .../ThreadedBulletinBoardClient.java | 11 +- .../SingleServerGetRedundancyWorker.java | 24 +- ...dedBulletinBoardClientIntegrationTest.java | 556 ------------------ .../LocalBulletinBoardClientTest.java | 107 ++++ .../sqlserver/BulletinBoardSQLServer.java | 96 ++- .../mappers/MessageCallbackHandler.java | 6 +- .../mappers/MessageStubCallbackHandler.java | 59 ++ .../webapp/BulletinBoardWebApp.java | 17 +- .../AsyncBulletinBoardClient.java | 13 +- .../bulletinboard/BulletinBoardClient.java | 15 +- .../bulletinboard/BulletinBoardConstants.java | 1 + .../bulletinboard/BulletinBoardServer.java | 11 +- .../BulletinBoardSubscriber.java | 32 + .../BulletinBoardSynchronizer.java | 22 + .../meerkat/bulletinboard/CompleteBatch.java | 5 + .../SubscriptionAsyncBulletinBoardClient.java | 7 + .../main/proto/meerkat/BulletinBoardAPI.proto | 12 + 19 files changed, 474 insertions(+), 606 deletions(-) delete mode 100644 bulletin-board-client/src/test/java/ThreadedBulletinBoardClientIntegrationTest.java create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubCallbackHandler.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSubscriber.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 633e495..2ed113a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -1,13 +1,21 @@ 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; @@ -129,6 +137,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ */ @Override public List readMessages(MessageFilterList filterList) { + WebTarget webTarget; Response response; BulletinBoardMessageList messageList; @@ -139,6 +148,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ } for (String db : meerkatDBs) { + try { webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH); @@ -151,9 +161,34 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ } } 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() { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 24cd6bf..34531cf 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -7,6 +7,7 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.BulletinBoardClientParams; import meerkat.util.BulletinBoardUtils; @@ -29,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; * If the list of servers contains more than one server: the server actually used is the first one * The class further implements a delayed access to the server after a communication error occurs */ -public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements AsyncBulletinBoardClient { +public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient { private final int MAX_RETRIES = 11; @@ -275,13 +276,13 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i class SubscriptionCallback implements FutureCallback> { private SingleServerReadMessagesWorker worker; - private final MessageHandler messageHandler; + private final FutureCallback> callback; private MessageFilterList.Builder filterBuilder; - public SubscriptionCallback(SingleServerReadMessagesWorker worker, MessageHandler messageHandler) { + public SubscriptionCallback(SingleServerReadMessagesWorker worker, FutureCallback> callback) { this.worker = worker; - this.messageHandler = messageHandler; + this.callback = callback; filterBuilder = worker.getPayload().toBuilder(); } @@ -290,7 +291,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void onSuccess(List result) { // Report new messages to user - messageHandler.handleNewMessages(result); + callback.onSuccess(result); // Remove last filter from list (MIN_ENTRY one) filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); @@ -315,14 +316,16 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Notify client about failure fail(); - // Reschedule exact same task - scheduleWorker(worker, this); + // Notify caller about failure and terminate subscription + callback.onFailure(t); } } - public SingleServerBulletinBoardClient(int threadPoolSize, long failDelayInMilliseconds, long subscriptionIntervalInMilliseconds) { + public SingleServerBulletinBoardClient(ListeningScheduledExecutorService executorService, + long failDelayInMilliseconds, + long subscriptionIntervalInMilliseconds) { - executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)); + this.executorService = executorService; this.failDelayInMilliseconds = failDelayInMilliseconds; this.subscriptionIntervalInMilliseconds = subscriptionIntervalInMilliseconds; @@ -332,6 +335,14 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } + public SingleServerBulletinBoardClient(int threadPoolSize, long failDelayInMilliseconds, long subscriptionIntervalInMilliseconds) { + + this(MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)), + failDelayInMilliseconds, + subscriptionIntervalInMilliseconds); + + } + /** * Stores database location, initializes the web Client and * @param clientParams contains the data needed to access the DBs @@ -567,8 +578,16 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) { + public void querySync(SyncQuery syncQuery, FutureCallback callback) { + SingleServerQuerySyncWorker worker = new SingleServerQuerySyncWorker(meerkatDBs.get(0), syncQuery, MAX_RETRIES); + + scheduleWorker(worker, new RetryCallback<>(worker, callback)); + + } + + @Override + public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { // Remove all existing MIN_ENTRY filters and create new one that starts at 0 MessageFilterList.Builder filterListBuilder = filterList.toBuilder(); @@ -583,15 +602,19 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } filterListBuilder.addFilter(MessageFilter.newBuilder() .setType(FilterType.MIN_ENTRY) - .setEntry(0) + .setEntry(startEntry) .build()); // Create job with no retries - SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterListBuilder.build(), 1); + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterListBuilder.build(), MAX_RETRIES); - // Submit job and create callback - scheduleWorker(worker, new SubscriptionCallback(worker, messageHandler)); + // Submit job and create callback that retries on failure and handles repeated subscription + scheduleWorker(worker, new RetryCallback<>(worker, new SubscriptionCallback(worker, callback))); + } + @Override + public void subscribe(MessageFilterList filterList, FutureCallback> callback) { + subscribe(filterList, 0, callback); } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index d8f66f2..52e28e0 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -5,6 +5,7 @@ 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.*; @@ -55,7 +56,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple batchDigest = new GenericBatchDigest(digest); - minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * clientParams.getBulletinBoardAddressCount()); + minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * (float) clientParams.getBulletinBoardAddressCount()); executorService = Executors.newFixedThreadPool(JOBS_THREAD_NUM); @@ -223,9 +224,13 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } + /** + * 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 subscribe(MessageFilterList filterList, MessageHandler messageHandler) { - // TODO: Implement + public void querySync(SyncQuery syncQuery, FutureCallback callback) { + callback.onFailure(new IllegalAccessError("querySync is not supported by this class")); } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java index 10517f7..0401a76 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java @@ -2,6 +2,7 @@ package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; +import meerkat.comm.MessageInputStream; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; @@ -11,6 +12,10 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; + import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; import static meerkat.bulletinboard.BulletinBoardConstants.READ_MESSAGES_PATH; @@ -45,17 +50,19 @@ public class SingleServerGetRedundancyWorker extends SingleServerWorker inputStream = null; // Retrieve answer try { - // If a BulletinBoardMessageList is returned: the read was successful - BulletinBoardMessageList msgList = response.readEntity(BulletinBoardMessageList.class); + inputStream = MessageInputStream.MessageInputStreamFactory.createMessageInputStream(in, BulletinBoardMessage.class); - if (msgList.getMessageList().size() > 0){ + if (inputStream.asList().size() > 0){ // Message exists in the server return 1.0f; } @@ -64,14 +71,15 @@ public class SingleServerGetRedundancyWorker extends SingleServerWorker thrown; - private Random random; - - // Constructor - - public ThreadedBulletinBoardClientIntegrationTest(){ - - signers = new GenericBatchDigitalSignature[2]; - signerIDs = new ByteString[signers.length]; - signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); - signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); - - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD1.toCharArray(); - - KeyStore.Builder keyStoreBuilder; - try { - keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); - - signers[0].loadSigningCertificate(keyStoreBuilder); - - signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); - password = KEYFILE_PASSWORD3.toCharArray(); - - keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); - signers[1].loadSigningCertificate(keyStoreBuilder); - - signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); - - for (int i = 0 ; i < signers.length ; i++) { - signerIDs[i] = signers[i].getSignerID(); - } - - } catch (IOException e) { - System.err.println("Failed reading from signature file " + e.getMessage()); - fail("Failed reading from signature file " + e.getMessage()); - } catch (CertificateException e) { - System.err.println("Failed reading certificate " + e.getMessage()); - fail("Failed reading certificate " + e.getMessage()); - } catch (KeyStoreException e) { - System.err.println("Failed reading keystore " + e.getMessage()); - fail("Failed reading keystore " + e.getMessage()); - } catch (NoSuchAlgorithmException e) { - System.err.println("Couldn't find signing algorithm " + e.getMessage()); - fail("Couldn't find signing algorithm " + e.getMessage()); - } catch (UnrecoverableKeyException e) { - System.err.println("Couldn't find signing key " + e.getMessage()); - fail("Couldn't find signing key " + e.getMessage()); - } - - } - - // Callback definitions - - protected void genericHandleFailure(Throwable t){ - System.err.println(t.getCause() + " " + t.getMessage()); - thrown.add(t); - jobSemaphore.release(); - } - - private class PostCallback implements FutureCallback{ - - private boolean isAssert; - private boolean assertValue; - - public PostCallback() { - this(false); - } - - public PostCallback(boolean isAssert) { - this(isAssert,true); - } - - public PostCallback(boolean isAssert, boolean assertValue) { - this.isAssert = isAssert; - this.assertValue = assertValue; - } - - @Override - public void onSuccess(Boolean msg) { - System.err.println("Post operation completed"); - jobSemaphore.release(); - //TODO: Change Assert mechanism to exception one - if (isAssert) { - if (assertValue) { - assertThat("Post operation failed", msg, is(Boolean.TRUE)); - } else { - assertThat("Post operation succeeded unexpectedly", msg, is(Boolean.FALSE)); - } - } - } - - @Override - public void onFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private class RedundancyCallback implements FutureCallback{ - - private float minRedundancy; - - public RedundancyCallback(float minRedundancy) { - this.minRedundancy = minRedundancy; - } - - @Override - public void onSuccess(Float redundancy) { - System.err.println("Redundancy found is: " + redundancy); - jobSemaphore.release(); - assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); - } - - @Override - public void onFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private class ReadCallback implements FutureCallback>{ - - private List expectedMsgList; - - public ReadCallback(List expectedMsgList) { - this.expectedMsgList = expectedMsgList; - } - - @Override - public void onSuccess(List messages) { - - System.err.println(messages); - jobSemaphore.release(); - - BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); - - assertThat(messages.size(), is(expectedMsgList.size())); - - Iterator expectedMessageIterator = expectedMsgList.iterator(); - Iterator receivedMessageIterator = messages.iterator(); - - while (expectedMessageIterator.hasNext()) { - assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); - } - - } - - @Override - public void onFailure(Throwable t) { - genericHandleFailure(t); - } - } - - private class ReadBatchCallback implements FutureCallback { - - private CompleteBatch expectedBatch; - - public ReadBatchCallback(CompleteBatch expectedBatch) { - this.expectedBatch = expectedBatch; - } - - @Override - public void onSuccess(CompleteBatch batch) { - - System.err.println(batch); - jobSemaphore.release(); - - assertThat("Batch returned is incorrect", batch, is(equalTo(expectedBatch))); - - } - - @Override - public void onFailure(Throwable t) { - genericHandleFailure(t); - } - } - - // Randomness generators - - private byte randomByte(){ - return (byte) random.nextInt(); - } - - private byte[] randomByteArray(int length) { - - byte[] randomBytes = new byte[length]; - - for (int i = 0; i < length ; i++){ - randomBytes[i] = randomByte(); - } - - return randomBytes; - - } - - private CompleteBatch createRandomBatch(int signer, int batchId, int length) throws SignatureException { - - CompleteBatch completeBatch = new CompleteBatch(); - - // Create data - - completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() - .setSignerId(signerIDs[signer]) - .setBatchId(batchId) - .addTag("Test") - .build()); - - for (int i = 0 ; i < length ; i++){ - - BatchData batchData = BatchData.newBuilder() - .setData(ByteString.copyFrom(randomByteArray(i))) - .build(); - - completeBatch.appendBatchData(batchData); - - } - - completeBatch.setTimestamp(Timestamp.newBuilder() - .setSeconds(Math.abs(90)) - .setNanos(50) - .build()); - - signers[signer].updateContent(completeBatch); - - completeBatch.setSignature(signers[signer].sign()); - - return completeBatch; - - } - - // Test methods - - /** - * Takes care of initializing the client and the test resources - */ - @Before - public void init(){ - - bulletinBoardClient = new ThreadedBulletinBoardClient(); - - random = new Random(0); // We use insecure randomness in tests for repeatability - - List testDB = new LinkedList<>(); - testDB.add(BASE_URL); - - bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() - .addAllBulletinBoardAddress(testDB) - .setMinRedundancy((float) 1.0) - .build()); - - postCallback = new PostCallback(); - redundancyCallback = new RedundancyCallback((float) 1.0); - - thrown = new Vector<>(); - jobSemaphore = new Semaphore(0); - - } - - /** - * Closes the client and makes sure the test fails when an exception occurred in a separate thread - */ - - @After - public void close() { - - bulletinBoardClient.close(); - - if (thrown.size() > 0) { - assert false; - } - - } - - /** - * Tests the standard post, redundancy and read methods - */ - @Test - public void postTest() { - - 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}; - - BulletinBoardMessage msg; - - MessageFilterList filterList; - List msgList; - - MessageID messageID; - - msg = BulletinBoardMessage.newBuilder() - .setMsg(UnsignedBulletinBoardMessage.newBuilder() - .addTag("Signature") - .addTag("Trustee") - .setData(ByteString.copyFrom(b1)) - .setTimestamp(Timestamp.newBuilder() - .setSeconds(20) - .setNanos(30) - .build()) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.DSA) - .setData(ByteString.copyFrom(b2)) - .setSignerId(ByteString.copyFrom(b3)) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.ECDSA) - .setData(ByteString.copyFrom(b3)) - .setSignerId(ByteString.copyFrom(b2)) - .build()) - .build(); - - messageID = bulletinBoardClient.postMessage(msg,postCallback); - - try { - jobSemaphore.acquire(); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - bulletinBoardClient.getRedundancy(messageID,redundancyCallback); - - filterList = MessageFilterList.newBuilder() - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Signature") - .build() - ) - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Trustee") - .build() - ) - .build(); - - msgList = new LinkedList<>(); - msgList.add(msg); - - readCallback = new ReadCallback(msgList); - - bulletinBoardClient.readMessages(filterList, readCallback); - try { - jobSemaphore.acquire(2); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - } - - /** - * Tests posting a batch by parts - * Also tests not being able to post to a closed batch - * @throws CommunicationException, SignatureException, InterruptedException - */ - @Test - public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { - - final int SIGNER = 1; - final int BATCH_ID = 100; - final int BATCH_LENGTH = 100; - - CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); - - // Begin batch - - bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), postCallback); - - jobSemaphore.acquire(); - - // Post data - - bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), postCallback); - - jobSemaphore.acquire(); - - // Close batch - - CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() - .setBatchId(BATCH_ID) - .setBatchLength(BATCH_LENGTH) - .setTimestamp(Timestamp.newBuilder() - .setSeconds(50) - .setNanos(80) - .build()) - .setSig(completeBatch.getSignature()) - .build(); - - bulletinBoardClient.closeBatch(closeBatchMessage, postCallback); - - jobSemaphore.acquire(); - - // Attempt to open batch again - - bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), failPostCallback); - - // Attempt to add batch data - - bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), failPostCallback); - - jobSemaphore.acquire(2); - - // Read batch data - - BatchSpecificationMessage batchSpecificationMessage = - BatchSpecificationMessage.newBuilder() - .setSignerId(signerIDs[SIGNER]) - .setBatchId(BATCH_ID) - .setStartPosition(0) - .build(); - - readBatchCallback = new ReadBatchCallback(completeBatch); - - bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); - - jobSemaphore.acquire(); - - } - - /** - * Posts a complete batch message - * Checks reading od the message - * @throws CommunicationException, SignatureException, InterruptedException - */ - @Test - public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { - - final int SIGNER = 0; - final int BATCH_ID = 101; - final int BATCH_LENGTH = 50; - - // Post batch - - CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); - - bulletinBoardClient.postBatch(completeBatch,postCallback); - - jobSemaphore.acquire(); - - // Read batch - - BatchSpecificationMessage batchSpecificationMessage = - BatchSpecificationMessage.newBuilder() - .setSignerId(signerIDs[SIGNER]) - .setBatchId(BATCH_ID) - .setStartPosition(0) - .build(); - - readBatchCallback = new ReadBatchCallback(completeBatch); - - bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); - - jobSemaphore.acquire(); - - } - - /** - * Tests that an unopened batch cannot be closed - * @throws CommunicationException, InterruptedException - */ - @Test - public void testInvalidBatchClose() throws CommunicationException, InterruptedException { - - final int NON_EXISTENT_BATCH_ID = 999; - - CloseBatchMessage closeBatchMessage = - CloseBatchMessage.newBuilder() - .setBatchId(NON_EXISTENT_BATCH_ID) - .setBatchLength(1) - .setSig(Crypto.Signature.getDefaultInstance()) - .setTimestamp(Timestamp.newBuilder() - .setSeconds(9) - .setNanos(12) - .build()) - .build(); - - // Try to close the (unopened) batch; - - bulletinBoardClient.closeBatch(closeBatchMessage, failPostCallback); - - jobSemaphore.acquire(); - - } - -} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java new file mode 100644 index 0000000..2e0e0af --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -0,0 +1,107 @@ +package meerkat.bulletinboard; + +import meerkat.bulletinboard.sqlserver.*; +import meerkat.comm.CommunicationException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.security.SignatureException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +import static org.junit.Assert.fail; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class LocalBulletinBoardClientTest { + + private static final int THREAD_NUM = 3; + private static final String DB_NAME = "TestDB"; + + // Tester + private GenericBulletinBoardClientTester clientTest; + + public LocalBulletinBoardClientTest() throws CommunicationException { + + H2QueryProvider queryProvider = new H2QueryProvider(DB_NAME) ; + + try { + + Connection conn = queryProvider.getDataSource().getConnection(); + Statement stmt = conn.createStatement(); + + List deletionQueries = queryProvider.getSchemaDeletionCommands(); + + for (String deletionQuery : deletionQueries) { + stmt.execute(deletionQuery); + } + + } catch (SQLException e) { + System.err.println(e.getMessage()); + throw new CommunicationException(e.getCause() + " " + e.getMessage()); + } + + BulletinBoardServer server = new BulletinBoardSQLServer(queryProvider); + server.init(DB_NAME); + + LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM); + + clientTest = new GenericBulletinBoardClientTester(client); + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + @Before + public void init(){ + + clientTest.init(); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + @After + public void close() { + + clientTest.close(); + + } + + @Test + public void postTest() { + + clientTest.postTest(); + + } + + @Test + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testBatchPost(); + } + + @Test + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testCompleteBatchPost(); + + } + + @Test + public void testInvalidBatchClose() throws CommunicationException, InterruptedException { + + clientTest.testInvalidBatchClose(); + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index c7bcf57..ab82ab1 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -5,6 +5,7 @@ import java.util.*; import com.google.protobuf.*; +import com.google.protobuf.Timestamp; import meerkat.bulletinboard.*; import meerkat.bulletinboard.sqlserver.mappers.*; import static meerkat.bulletinboard.BulletinBoardConstants.*; @@ -26,6 +27,7 @@ import javax.sql.DataSource; import meerkat.util.BulletinBoardUtils; import meerkat.util.TimestampComparator; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -586,14 +588,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } - /** - * Used to retrieve just basic information about messages to allow calculation of checksum + * Private implementation of the message stub reader for returning result as a list * @param filterList is a filter list that defines which messages the client is interested in - * @return a list of Bulletin Board Messages that contain just the entry number, timestamp and message ID for each message - * The message ID is returned inside the message data field + * @return the requested list of message stubs */ - protected List readMessageStubs(MessageFilterList filterList) { + private List readMessageStubs(MessageFilterList filterList) { StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); @@ -635,6 +635,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** * This method returns a string representation of the tag associated with a batch ID * @param batchId is the given batch ID @@ -644,6 +645,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return BATCH_ID_TAG_PREFIX + Integer.toString(batchId); } + /** * This method checks if a specified batch exists and is already closed * @param signerId is the ID of the publisher of the batch @@ -687,6 +689,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + @Override public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException { @@ -719,8 +722,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ jdbcTemplate.batchUpdate(sql,namedParameters); return BoolMsg.newBuilder().setValue(true).build(); + } + @Override public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException{ @@ -744,6 +749,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + @Override public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException { @@ -767,13 +773,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return BoolMsg.newBuilder().setValue(false).build(); } - // Get Tags and add them to CompleteBatch sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_TAGS); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId); + namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId.toByteArray()); namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(1),batchId); List tags = jdbcTemplate.query(sql, namedParameters, new StringMapper()); @@ -847,6 +852,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return BoolMsg.newBuilder().setValue(true).build(); } + @Override public void readBatch(BatchSpecificationMessage message, MessageOutputStream out) throws CommunicationException, IllegalArgumentException{ @@ -866,6 +872,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** * Finds the entry number of the last entry in the database * @return the entry number, or -1 if no entries are found @@ -884,10 +891,80 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + @Override + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) { + + if (generateSyncQueryParams == null + || !generateSyncQueryParams.hasFilterList() + || generateSyncQueryParams.getFilterList().getFilterCount() <= 0 + || generateSyncQueryParams.getBreakpointListCount() <= 0){ + + return SyncQuery.getDefaultInstance(); + + } + + List messages = readMessageStubs(generateSyncQueryParams.getFilterList()); + + if (messages.size() <= 0){ + return SyncQuery.newBuilder().build(); + } + + SyncQuery.Builder resultBuilder = SyncQuery.newBuilder(); + + Iterator messageIterator = messages.iterator(); + Iterator breakpointIterator = generateSyncQueryParams.getBreakpointListList().iterator(); + + Checksum checksum = new SimpleChecksum(); + checksum.setDigest(new SHA256Digest()); + + Timestamp lastTimestamp = Timestamp.getDefaultInstance(); + BulletinBoardMessage message = messageIterator.next(); + long currentMessageNum = 1; + + boolean checksumChanged = true; + + while (breakpointIterator.hasNext()){ + + Float breakpoint = breakpointIterator.next(); + + // Continue while breakpoint not reached, or it has been reached but no new timestamp has been encountered since + while ( messageIterator.hasNext() + && ((float) currentMessageNum / (float) messages.size() <= breakpoint) + || ((float) currentMessageNum / (float) messages.size() > breakpoint + && lastTimestamp.equals(message.getMsg().getTimestamp()))){ + + checksumChanged = true; + + checksum.update(message.getMsg().getData()); + + lastTimestamp = message.getMsg().getTimestamp(); + message = messageIterator.next(); + + } + + if (checksumChanged) { + + checksum.update(message.getMsg().getData()); + resultBuilder.addQuery(SingleSyncQuery.newBuilder() + .setTimeOfSync(message.getMsg().getTimestamp()) + .setChecksum(checksum.getChecksum()) + .build()); + + } + + checksumChanged = false; + + } + + return resultBuilder.build(); + + } + + /** * Searches for the latest time of sync of the DB relative to a given query and returns the metadata needed to complete the sync - * The checksum up to (and including) each given timestamp is calculated using bitwise XOR on 8-byte sized blocks of the message IDs - * @param syncQuery contains a succinct representation of states to compare to + * The checksum up to (and including) each given timestamp is calculated using an instance of SimpleChecksum + * @param syncQuery contains a succinct representation of states to compare against * @return the current last entry num and latest time of sync if there is one; -1 as last entry and empty timestamp otherwise * @throws CommunicationException */ @@ -960,6 +1037,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + @Override public void close() {} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java index bdba241..71ba742 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageCallbackHandler.java @@ -20,9 +20,9 @@ import java.util.List; */ public class MessageCallbackHandler implements RowCallbackHandler { - NamedParameterJdbcTemplate jdbcTemplate; - SQLQueryProvider sqlQueryProvider; - MessageOutputStream out; + private final NamedParameterJdbcTemplate jdbcTemplate; + private final SQLQueryProvider sqlQueryProvider; + private final MessageOutputStream out; public MessageCallbackHandler(NamedParameterJdbcTemplate jdbcTemplate, SQLQueryProvider sqlQueryProvider, MessageOutputStream out) { diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubCallbackHandler.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubCallbackHandler.java new file mode 100644 index 0000000..f81cc76 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubCallbackHandler.java @@ -0,0 +1,59 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider.QueryType; +import meerkat.comm.MessageOutputStream; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; +import meerkat.protobuf.Crypto; +import meerkat.util.BulletinBoardUtils; +import org.springframework.jdbc.core.RowCallbackHandler; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; + +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 21-Feb-16. + */ +public class MessageStubCallbackHandler implements RowCallbackHandler { + + private final MessageOutputStream out; + + public MessageStubCallbackHandler(MessageOutputStream out) { + + this.out = out; + + } + + @Override + public void processRow(ResultSet rs) throws SQLException { + + BulletinBoardMessage result; + + result = BulletinBoardMessage.newBuilder() + .setEntryNum(rs.getLong(1)) + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .setData(ByteString.copyFrom(rs.getBytes(2))) + .setTimestamp(BulletinBoardUtils.toTimestampProto(rs.getTimestamp(3))) + .build()) + .build(); + + try { + + out.writeMessage(result); + + } catch (IOException e) { + + //TODO: log + e.printStackTrace(); + + } + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 2e4782f..7c0f7fa 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -22,7 +22,7 @@ import static meerkat.rest.Constants.*; import java.io.IOException; import java.io.OutputStream; -import java.util.List; +import java.util.Collection; /** * An implementation of the BulletinBoardServer which functions as a WebApp @@ -183,6 +183,21 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } } + @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) diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index c6e330c..d74c1ea 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -11,10 +11,6 @@ import java.util.List; */ public interface AsyncBulletinBoardClient extends BulletinBoardClient { - public interface MessageHandler { - void handleNewMessages(List messageList); - } - /** * Post a message to the bulletin board in an asynchronous manner * @param msg is the message to be posted @@ -100,11 +96,12 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { */ public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback); + /** - * Subscribes to a notifier that will return any new messages on the server that match the given filters - * @param filterList defines the set of filters for message retrieval - * @param messageHandler defines the handler for new messages received + * Perform a Sync Query on the bulletin board + * @param syncQuery defines the query + * @param callback is a callback for handling the result of the query */ - public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); + public void querySync(SyncQuery syncQuery, FutureCallback callback); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 2f5a3df..245eddf 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -5,6 +5,7 @@ import meerkat.protobuf.Voting.*; import static meerkat.protobuf.BulletinBoardAPI.*; +import java.util.Collection; import java.util.List; /** @@ -26,8 +27,6 @@ public interface BulletinBoardClient { */ 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 @@ -40,11 +39,21 @@ public interface BulletinBoardClient { * 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). + * @param filterList return only messages that match the filters (null means no filtering) * @return the list of messages */ List 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. diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java index 66652f8..9ddee90 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -8,6 +8,7 @@ public interface BulletinBoardConstants { // Relative addresses for Bulletin Board operations public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; + public static final String GENERATE_SYNC_QUERY_PATH = "/generatesyncquery"; public static final String READ_MESSAGES_PATH = "/readmessages"; public static final String READ_BATCH_PATH = "/readbatch"; public static final String POST_MESSAGE_PATH = "/postmessage"; diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index 0b279c2..e458dbc 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -4,6 +4,8 @@ import meerkat.comm.CommunicationException; import meerkat.comm.MessageOutputStream; import meerkat.protobuf.BulletinBoardAPI.*; +import java.util.Collection; + /** * Created by Arbel on 07/11/15. @@ -28,7 +30,7 @@ public interface BulletinBoardServer{ * @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) @@ -77,6 +79,13 @@ public interface BulletinBoardServer{ */ public void readBatch(BatchSpecificationMessage message, MessageOutputStream 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 diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSubscriber.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSubscriber.java new file mode 100644 index 0000000..85eb2cc --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSubscriber.java @@ -0,0 +1,32 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 03-Mar-16. + * This interface defines the behaviour required from a subscription service to Bulletin Board messages + */ +public interface BulletinBoardSubscriber { + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * In case of communication error: the subscription is terminated + * @param filterList defines the set of filters for message retrieval + * @param callback defines how to handle new messages received and/or a failures in communication + */ + public void subscribe(MessageFilterList filterList, FutureCallback> callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * In case of communication error: the subscription is terminated + * @param filterList defines the set of filters for message retrieval + * @param startEntry defines the first entry number to consider + * @param callback defines how to handle new messages received and/or a failures in communication + */ + public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java new file mode 100644 index 0000000..4b07225 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java @@ -0,0 +1,22 @@ +package meerkat.bulletinboard; + +/** + * Created by Arbel Deutsch Peled on 08-Mar-16. + * This interface defines the behaviour of a bulletin board synchronizer + * This is used to make sure that data in a specific instance of a bulletin board server is duplicated to a sufficient percentage of the other servers + */ +public interface BulletinBoardSynchronizer extends Runnable{ + + /** + * + * @param localClient is a client for the local DB instance + * @param remoteClient is a client for the remote DBs + * @param minRedundancy + */ + public void init(BulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient, float minRedundancy); + + @Override + public void run(); + + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 14e87e7..649fd8b 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -139,7 +139,12 @@ public class CompleteBatch { @Override public String toString() { + + if (beginBatchMessage == null || beginBatchMessage.getSignerId() == null) + return "Unspecified batch " + super.toString(); + return "Batch " + beginBatchMessage.getSignerId().toString() + ":" + beginBatchMessage.getBatchId(); + } } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java new file mode 100644 index 0000000..b07e655 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java @@ -0,0 +1,7 @@ +package meerkat.bulletinboard; + +/** + * Created by Arbel Deutsch Peled on 03-Mar-16. + */ +public interface SubscriptionAsyncBulletinBoardClient extends AsyncBulletinBoardClient, BulletinBoardSubscriber { +} diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index fd95503..1136e16 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -146,6 +146,18 @@ message SyncQuery { } +// 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 { From 5f45c1f6d6e088b3743f9560dae2dc863cdf5d59 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Tue, 22 Mar 2016 00:49:21 +0200 Subject: [PATCH 031/106] tested with malicious users --- .../src/main/java/Communication/Network.java | 13 +- .../DistributedKeyGenerationUserImpl.java | 4 +- .../ShamirSecretSharing/SecretSharing.java | 3 +- .../JointFeldmanProtocol/DKGDeepTest.java | 174 ++++++++++++++++++ .../DKGMaliciousUserImpl.java | 72 ++++++++ .../java/JointFeldmanProtocol/DKGTest.java | 10 +- .../SDKGTest.java | 11 +- .../SDKGUserImplAbort.java | 2 + 8 files changed, 275 insertions(+), 14 deletions(-) create mode 100644 destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java create mode 100644 destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java rename destributed-key-generation/src/test/java/{ => SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem}/SDKGTest.java (94%) rename destributed-key-generation/src/test/java/{ => SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem}/SDKGUserImplAbort.java (95%) diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java index af7e5d6..ca53991 100644 --- a/destributed-key-generation/src/main/java/Communication/Network.java +++ b/destributed-key-generation/src/main/java/Communication/Network.java @@ -3,7 +3,10 @@ package Communication; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages.*; + +import java.util.HashSet; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; /** * Created by Tzlil on 2/7/2016. @@ -15,23 +18,23 @@ public class Network { protected final User[] users; protected final int n; - protected final Queue availableIDs; + protected final Set availableIDs; public static final int BROADCAST = 0; public Network(int n) { this.n = n; this.users = new User[n]; - this.availableIDs = new ArrayBlockingQueue(n); + this.availableIDs = new HashSet(); for (int id = 1; id <= n; id++){ availableIDs.add(id); } } - public User connect(MailHandler mailHandler){ - Integer id = availableIDs.poll(); - if (id == null) + public User connect(MailHandler mailHandler,int id){ + if (!availableIDs.contains(id)) return null; + availableIDs.remove(id); users[id - 1] = new User(id,this,mailHandler); return users[id - 1]; } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java index f633258..578b1e5 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -50,7 +50,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio this.messageHandler = new MessageHandler(); mailHandler.setMessageHandler(this.messageHandler); - this.user = network.connect(mailHandler); + this.user = network.connect(mailHandler,dkg.getId()); this.parties = dkg.getParties(); this.parties[id - 1].share = dkg.getShare(id); @@ -230,7 +230,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ int i = sender; int j = complaintMessage.getId(); - parties[i - 1].complaints[j - 1] = ComplainState.Waiting; + parties[j - 1].complaints[i - 1] = ComplainState.Waiting; } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index cdd631d..877d272 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -1,6 +1,7 @@ package ShamirSecretSharing; import Arithmetics.Arithmetic; +import Arithmetics.Fp; import java.math.BigInteger; import java.util.Random; @@ -45,7 +46,7 @@ public class SecretSharing{ for (int i = 1 ; i <= t; i++ ){ coefficients[i] = new BigInteger(bits,random).mod(q); } - return new Polynomial(coefficients); + return new Polynomial(coefficients,new Fp(q)); } /** diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java new file mode 100644 index 0000000..a50c75c --- /dev/null +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java @@ -0,0 +1,174 @@ +package JointFeldmanProtocol; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import UserInterface.DistributedKeyGenerationUser; +import org.factcenter.qilin.primitives.Group; +import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Array; +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 DKGDeepTest { + + int tests = 10; + BigInteger p = BigInteger.valueOf(2903); + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + + Testable[] testables; + + @Before + public void settings(){ + testables = new Testable[n]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); + } + } + + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + 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.QUAL){ + if(!testable.aborted.contains(i)) + assert (testable.dkgs[i - 1].getPublicValue().equals(publicValue)); + } + + // assert valid verification values + BigInteger expected,verification; + for (int i: testable.QUAL){ + if(!testable.aborted.contains(i)) { + expected = group.multiply(testable.g, testable.dkgs[i - 1].getShare().y); + verification = VerifiableSecretSharing.verify(i, testable.dkgs[i - 1].getCommitments(), group); + assert (expected.equals(verification)); + } + } + + + // restore the secret from shares + ArrayList sharesList = new ArrayList(); + + for(int i : testable.QUAL){ + if(!testable.aborted.contains(i)) + 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.restoreSecret(shares,arithmetic); + assert (calculatedSecret.equals(testable.secret)); + } + + @Test + public void test() throws Exception { + for (int i = 0; i < tests; i++){ + oneTest(i); + } + } + + class Testable{ + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] dkgs; + Thread[] threads; + BigInteger g; + BigInteger secret; + public Testable(Random random) { + + this.dkgs = new DistributedKeyGenerationUserImpl[n]; + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + Network network = new Network(n); + int id; + BigInteger s; + DistributedKeyGeneration dkg; + this.secret = BigInteger.ZERO; + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); + dkgs[id - 1] = randomDKGUser(id,network,dkg,random); + threads[id - 1] = new Thread(dkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ + if (QUAL.size() <= t) { + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + 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,network,abortStage); + case 2:// malicious + malicious.add(id); + return new DKGMaliciousUserImpl(dkg,network,random); + 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); + } + + + } +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java new file mode 100644 index 0000000..e3261f8 --- /dev/null +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java @@ -0,0 +1,72 @@ +package JointFeldmanProtocol; + +import Communication.MailHandler; +import Communication.Network; + +import java.math.BigInteger; +import java.util.*; + +/** + * Created by Tzlil on 3/21/2016. + */ +public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { + + private final DistributedKeyGeneration maliciousDkg; + private final Set falls; + public DKGMaliciousUserImpl(DistributedKeyGeneration dkg, Network network, Random random) { + super(dkg, network); + this.falls = selectFalls(random); + this.maliciousDkg = new DistributedKeyGeneration(t,n,randomInt(random),random,dkg.getQ(),g,group,id); + maliciousDkg.setParties(parties); + } + + public Set selectFalls(Random random){ + ArrayList ids = new ArrayList(); + for (int i = 1; i<= n ; i++){ + if(i!=id) { + ids.add(i); + } + } + Set falls = new HashSet(); + int fallsSize = random.nextInt(ids.size()) + 1;// 1 - (n-1) + while (falls.size() < fallsSize){ + falls.add(ids.remove(random.nextInt(ids.size()))); + } + return falls; + } + + @Override + public void stage1() { + dkg.broadcastCommitments(user); + sendSecrets(); //insteadof dkg.sendSecrets(user); + } + + @Override + public void stage3() { + maliciousDkg.answerAllComplainingPlayers(user); + } + + @Override + public void stage4(){ + // do nothing + } + + private BigInteger randomInt(Random random){ + BigInteger q = dkg.getQ(); + return new BigInteger(q.bitLength(), random).mod(q); + } + + private void sendSecrets(){ + for (int j = 1; j <= n ; j++){ + if(j != id){ + if(falls.contains(j)){ + maliciousDkg.sendSecret(user,j); + }else { + dkg.sendSecret(user, j); + } + } + } + } + + +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index b74f258..b50c46e 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -1,5 +1,7 @@ package JointFeldmanProtocol; +import Arithmetics.Arithmetic; +import Arithmetics.Fp; import Arithmetics.Z; import Communication.Network; import ShamirSecretSharing.Polynomial; @@ -27,10 +29,12 @@ public class DKGTest { BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); BigInteger[] secrets; Set QUAL = new HashSet(); + Arithmetic arithmetic; @Before public void settings(){ Zpstar zpstar = new Zpstar(p); Random random = new Random(); + arithmetic = new Fp(q); BigInteger g; int t = 9; int n = 20; @@ -39,7 +43,7 @@ public class DKGTest { threadsArrays = new Thread[tests][n]; secrets = new BigInteger[tests]; DistributedKeyGeneration dkg; - int abortedStage = 2; + int abortedStage = 1; for (int test = 0; test < tests; test++) { do { g = zpstar.sample(random); @@ -51,7 +55,7 @@ public class DKGTest { dkg = new DistributedKeyGeneration(t,n,secret,random,q,g,zpstar,i); if(i == n) { - dkgsArrays[test][i - 1] = new DKGUserImplAbort(dkg, network, abortedStage); + dkgsArrays[test][i - 1] = new DKGMaliciousUserImpl(dkg,network,random);//new DKGUserImplAbort(dkg, network, abortedStage); } else { dkgsArrays[test][i - 1] = new DistributedKeyGenerationUserImpl(dkg, network); @@ -104,7 +108,7 @@ public class DKGTest { shares[i] = sharesList.get(i); } - BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,new Z()).mod(q); + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,arithmetic); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/SDKGTest.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java similarity index 94% rename from destributed-key-generation/src/test/java/SDKGTest.java rename to destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java index 5866063..107f87c 100644 --- a/destributed-key-generation/src/test/java/SDKGTest.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java @@ -1,8 +1,10 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; import Arithmetics.Z; import Communication.Network; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; import UserInterface.DistributedKeyGenerationUser; @@ -31,10 +33,13 @@ public class SDKGTest { Set QUAL = new HashSet(); + Arithmetic arithmetic; + @Before public void settings(){ Zpstar zpstar = new Zpstar(p); Random random = new Random(); + arithmetic = new Fp(q); BigInteger g,h; int t = 9; int n = 20; @@ -108,7 +113,7 @@ public class SDKGTest { shares[i] = sharesList.get(i); } - BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,new Z()).mod(q); + BigInteger calculatedSecret = SecretSharing.restoreSecret(shares,arithmetic); assert (calculatedSecret.equals(secret)); } diff --git a/destributed-key-generation/src/test/java/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java similarity index 95% rename from destributed-key-generation/src/test/java/SDKGUserImplAbort.java rename to destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java index bc30eb5..fc777d3 100644 --- a/destributed-key-generation/src/test/java/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java @@ -1,3 +1,5 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + import Communication.Network; import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; From e56312d38bae20ae1a02726f23eeef9d222eb02b Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Tue, 22 Mar 2016 10:16:46 +0200 Subject: [PATCH 032/106] Local Client supports subsrciptions --- .../GenericSubscriptionClientTester.java | 231 ++++++++++++++++++ .../LocalBulletinBoardClientTest.java | 17 +- .../sqlserver/H2QueryProvider.java | 9 +- .../util/BulletinBoardMessageGenerator.java | 34 ++- 4 files changed, 279 insertions(+), 12 deletions(-) create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java new file mode 100644 index 0000000..a91f8d6 --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java @@ -0,0 +1,231 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; +import meerkat.comm.CommunicationException; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.util.BulletinBoardMessageComparator; +import meerkat.util.BulletinBoardMessageGenerator; + +import java.io.IOException; +import java.io.InputStream; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.*; +import java.util.concurrent.Semaphore; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * Created by Arbel Deutsch Peled on 22-Mar-16. + */ +public class GenericSubscriptionClientTester { + + private GenericBatchDigitalSignature signers[]; + private ByteString[] signerIDs; + + private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12"; + + private static String KEYFILE_PASSWORD1 = "secret"; + private static String KEYFILE_PASSWORD3 = "shh"; + + private static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + private static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; + + private SubscriptionAsyncBulletinBoardClient bulletinBoardClient; + + private Random random; + private BulletinBoardMessageGenerator generator; + + private Semaphore jobSemaphore; + private Vector thrown; + + public GenericSubscriptionClientTester(SubscriptionAsyncBulletinBoardClient bulletinBoardClient){ + + this.bulletinBoardClient = bulletinBoardClient; + + signers = new GenericBatchDigitalSignature[2]; + signerIDs = new ByteString[signers.length]; + signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); + + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD1.toCharArray(); + + KeyStore.Builder keyStoreBuilder; + try { + keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); + + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); + password = KEYFILE_PASSWORD3.toCharArray(); + + keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); + signers[1].loadSigningCertificate(keyStoreBuilder); + + signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + + for (int i = 0 ; i < signers.length ; i++) { + signerIDs[i] = signers[i].getSignerID(); + } + + } catch (IOException e) { + System.err.println("Failed reading from signature file " + e.getMessage()); + fail("Failed reading from signature file " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("Failed reading certificate " + e.getMessage()); + fail("Failed reading certificate " + e.getMessage()); + } catch (KeyStoreException e) { + System.err.println("Failed reading keystore " + e.getMessage()); + fail("Failed reading keystore " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.err.println("Couldn't find signing algorithm " + e.getMessage()); + fail("Couldn't find signing algorithm " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + System.err.println("Couldn't find signing key " + e.getMessage()); + fail("Couldn't find signing key " + e.getMessage()); + } + + } + + /** + * Takes care of initializing the client and the test resources + */ + public void init(){ + + random = new Random(0); // We use insecure randomness in tests for repeatability + generator = new BulletinBoardMessageGenerator(random); + + thrown = new Vector<>(); + jobSemaphore = new Semaphore(0); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + public void close() { + + if (thrown.size() > 0) { + assert false; + } + + } + + private class SubscriptionCallback implements FutureCallback>{ + + private int stage; + private final List> expectedMessages; + private final List messagesToPost; + private final BulletinBoardMessageComparator comparator; + + public SubscriptionCallback(List> expectedMessages, List messagesToPost) { + + this.expectedMessages = expectedMessages; + this.messagesToPost = messagesToPost; + this.stage = 0; + this.comparator = new BulletinBoardMessageComparator(); + + } + + @Override + public void onSuccess(List result) { + + if (stage >= expectedMessages.size()) + return; + + // Check for consistency + + List expectedMsgList = expectedMessages.get(stage); + + if (expectedMsgList.size() != result.size()){ + onFailure(new AssertionError("Received wrong number of messages")); + return; + } + + Iterator expectedMessageIterator = expectedMsgList.iterator(); + Iterator receivedMessageIterator = result.iterator(); + + while (expectedMessageIterator.hasNext()) { + if(comparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()) != 0){ + onFailure(new AssertionError("Received unexpected message")); + return; + } + } + + // Post new message + try { + if (stage < messagesToPost.size()) { + bulletinBoardClient.postMessage(messagesToPost.get(stage)); + } + } catch (CommunicationException e) { + onFailure(e); + return; + } + + stage++; + jobSemaphore.release(); + } + + @Override + public void onFailure(Throwable t) { + System.err.println(t.getCause() + " " + t.getMessage()); + thrown.add(t); + jobSemaphore.release(expectedMessages.size()); + stage = expectedMessages.size(); + } + } + + public void subscriptionTest() throws SignatureException, CommunicationException { + + final int FIRST_POST_ID = 201; + final int SECOND_POST_ID = 202; + final String COMMON_TAG = "SUBSCRIPTION_TEST"; + + List tags = new LinkedList<>(); + tags.add(COMMON_TAG); + + BulletinBoardMessage msg1 = generator.generateRandomMessage(signers, Timestamp.newBuilder().setSeconds(1000).setNanos(900).build(), 10, 4, tags); + BulletinBoardMessage msg2 = generator.generateRandomMessage(signers, Timestamp.newBuilder().setSeconds(800).setNanos(300).build(), 10, 4); + BulletinBoardMessage msg3 = generator.generateRandomMessage(signers, Timestamp.newBuilder().setSeconds(2000).setNanos(0).build(), 10, 4, tags); + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(COMMON_TAG) + .build()) + .build(); + + List> expectedMessages = new ArrayList<>(3); + expectedMessages.add(new LinkedList()); + expectedMessages.add(new LinkedList()); + expectedMessages.add(new LinkedList()); + expectedMessages.get(0).add(msg1); + expectedMessages.get(2).add(msg3); + + List messagesToPost = new ArrayList<>(2); + messagesToPost.add(msg2); + messagesToPost.add(msg3); + + bulletinBoardClient.postMessage(msg1); + bulletinBoardClient.subscribe(filterList, new SubscriptionCallback(expectedMessages, messagesToPost)); + + try { + jobSemaphore.acquire(3); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + } + +} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index 2e0e0af..d2039ae 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -22,8 +22,11 @@ public class LocalBulletinBoardClientTest { private static final int THREAD_NUM = 3; private static final String DB_NAME = "TestDB"; - // Tester + private static final int SUBSRCIPTION_DELAY = 3000; + + // Testers private GenericBulletinBoardClientTester clientTest; + private GenericSubscriptionClientTester subscriptionTester; public LocalBulletinBoardClientTest() throws CommunicationException { @@ -48,8 +51,8 @@ public class LocalBulletinBoardClientTest { BulletinBoardServer server = new BulletinBoardSQLServer(queryProvider); server.init(DB_NAME); - LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM); - + LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM, SUBSRCIPTION_DELAY); + subscriptionTester = new GenericSubscriptionClientTester(client); clientTest = new GenericBulletinBoardClientTester(client); } @@ -104,4 +107,12 @@ public class LocalBulletinBoardClientTest { } + @Test + public void testSubscription() throws SignatureException, CommunicationException { + subscriptionTester.init(); + subscriptionTester.subscriptionTest(); + subscriptionTester.close(); + + } + } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index c390048..a54c2ff 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -158,10 +158,10 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider + " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)"; case BEFORE_TIME: - return "MsgTable.ExactTime <= :TimeStamp"; + return "MsgTable.ExactTime <= :TimeStamp" + serialString; case AFTER_TIME: - return "MsgTable.ExactTime >= :TimeStamp"; + return "MsgTable.ExactTime >= :TimeStamp" + serialString; default: throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); @@ -186,6 +186,11 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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); } diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java index 5ca3e0b..dff562e 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java @@ -8,6 +8,8 @@ import com.google.protobuf.Timestamp; import java.math.BigInteger; import java.security.SignatureException; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import java.util.Random; /** @@ -36,35 +38,36 @@ public class BulletinBoardMessageGenerator { * @param timestamp contains the time used in the message * @param dataSize is the length of the data contained in the message * @param tagNumber is the number of tags to generate + * @param tags is a list of initial tags (on top of which more will be added according to the method input) * @return a random, signed Bulletin Board Message containing random data and tags and the given timestamp */ - - public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, Timestamp timestamp, int dataSize, int tagNumber) - throws SignatureException { + public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, Timestamp timestamp, int dataSize, int tagNumber, List tags) + throws SignatureException{ // Generate random data. byte[] data = new byte[dataSize]; - String[] tags = new String[tagNumber]; + String[] newTags = new String[tagNumber]; for (int i = 0; i < dataSize; i++) { data[i] = randomByte(); } for (int i = 0; i < tagNumber; i++) { - tags[i] = randomString(); + newTags[i] = randomString(); } UnsignedBulletinBoardMessage unsignedMessage = UnsignedBulletinBoardMessage.newBuilder() .setData(ByteString.copyFrom(data)) .setTimestamp(timestamp) - .addAllTag(Arrays.asList(tags)) + .addAllTag(tags) + .addAllTag(Arrays.asList(newTags)) .build(); BulletinBoardMessage.Builder messageBuilder = BulletinBoardMessage.newBuilder() - .setMsg(unsignedMessage); + .setMsg(unsignedMessage); for (int i = 0 ; i < signers.length ; i++) { signers[i].updateContent(unsignedMessage); @@ -75,6 +78,23 @@ public class BulletinBoardMessageGenerator { } + /** + * Generates a complete instance of a BulletinBoardMessage + * @param signers contains the (possibly multiple) credentials required to sign the message + * @param timestamp contains the time used in the message + * @param dataSize is the length of the data contained in the message + * @param tagNumber is the number of tags to generate + * @return a random, signed Bulletin Board Message containing random data and tags and the given timestamp + */ + + public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, Timestamp timestamp, int dataSize, int tagNumber) + throws SignatureException { + + List tags = new LinkedList<>(); + return generateRandomMessage(signers, timestamp, dataSize, tagNumber, tags); + + } + /** * Generates a complete instance of a BulletinBoardMessage * @param signers contains the (possibly multiple) credentials required to sign the message From 49c1e2c17856e674d9fb06a2d298117537b39ed9 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 27 Mar 2016 20:11:09 +0300 Subject: [PATCH 033/106] Added missing files to version control --- bulletin-board-client/build.gradle | 242 ++++++++ .../CachedBulletinBoardClient.java | 168 ++++++ .../LocalBulletinBoardClient.java | 531 ++++++++++++++++++ .../ThreadedBulletinBoardSubscriber.java | 272 +++++++++ .../GenericBulletinBoardClientTester.java | 519 +++++++++++++++++ ...dedBulletinBoardClientIntegrationTest.java | 95 ++++ 6 files changed, 1827 insertions(+) create mode 100644 bulletin-board-client/build.gradle create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java diff --git a/bulletin-board-client/build.gradle b/bulletin-board-client/build.gradle new file mode 100644 index 0000000..8fdeba0 --- /dev/null +++ b/bulletin-board-client/build.gradle @@ -0,0 +1,242 @@ + +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: '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 = "Meerkat Voting Common Library" + +// Your project version +version = "0.0" + +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.+' + compile 'org.xerial:sqlite-jdbc:3.7.+' + + // Logging + compile 'org.slf4j:slf4j-api:1.7.7' + runtime 'ch.qos.logback:logback-classic:1.1.2' + runtime 'ch.qos.logback:logback-core:1.1.2' + + // Google protobufs + compile 'com.google.protobuf:protobuf-java:3.+' + + // Crypto + compile 'org.factcenter.qilin:qilin:1.1+' + compile 'org.bouncycastle:bcprov-jdk15on:1.53' + compile 'org.bouncycastle:bcpkix-jdk15on:1.53' + + // Depend on test resources from meerkat-common + testCompile project(path: ':meerkat-common', configuration: 'testOutput') + + // Depend on server compilation for the non-integration tests + testCompile project(path: ':bulletin-board-server') + + testCompile 'junit:junit:4.+' + testCompile 'org.hamcrest:hamcrest-all:1.3' + + runtime 'org.codehaus.groovy:groovy:2.4.+' +} + +test { + exclude '**/*IntegrationTest*' + outputs.upToDateWhen { false } +} + +task integrationTest(type: Test) { + include '**/*IntegrationTest*' +// debug = true + outputs.upToDateWhen { false } + +} + +/*==== 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 + *===================================*/ + +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 { + + 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 + } + } + } +} + + + diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java new file mode 100644 index 0000000..96ba76d --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -0,0 +1,168 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListeningScheduledExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.ByteString; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Voting.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Executors; + +/** + * Created by Arbel Deutsch Peled on 03-Mar-16. + * This is a full-fledged implementation of a Bulletin Board Client + * It provides asynchronous access to several remote servers, as well as a local cache + * Read/write operations are performed on the local server + * After any read is carried out, a subscription is made for the specific query to make sure the local DB will be updated + * The database also employs a synchronizer which makes sure local data is sent to the remote servers + */ +public class CachedBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient { + + private final BulletinBoardClient localClient; + private AsyncBulletinBoardClient remoteClient; + private BulletinBoardSubscriber subscriber; + + private final int threadPoolSize; + private final long failDelayInMilliseconds; + private final long subscriptionIntervalInMilliseconds; + + public CachedBulletinBoardClient(BulletinBoardClient localClient, + int threadPoolSize, + long failDelayInMilliseconds, + long subscriptionIntervalInMilliseconds) + throws IllegalAccessException, InstantiationException { + + this.localClient = localClient; + this.threadPoolSize = threadPoolSize; + this.failDelayInMilliseconds = failDelayInMilliseconds; + this.subscriptionIntervalInMilliseconds = subscriptionIntervalInMilliseconds; + + remoteClient = new ThreadedBulletinBoardClient(); + + } + + @Override + public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback) { + return null; + } + + @Override + public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { + return null; + } + + @Override + public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback) { + + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback) { + + } + + @Override + public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + + } + + @Override + public void getRedundancy(MessageID id, FutureCallback callback) { + + } + + @Override + public void readMessages(MessageFilterList filterList, FutureCallback> callback) { + + } + + @Override + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + + } + + @Override + public void querySync(SyncQuery syncQuery, FutureCallback callback) { + + } + + @Override + public void init(BulletinBoardClientParams clientParams) { + + remoteClient.init(clientParams); + + ListeningScheduledExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)); + + List subscriberClients = new ArrayList<>(clientParams.getBulletinBoardAddressCount()); + + for (String address : clientParams.getBulletinBoardAddressList()){ + + SubscriptionAsyncBulletinBoardClient newClient = + new SingleServerBulletinBoardClient(executorService, failDelayInMilliseconds, subscriptionIntervalInMilliseconds); + + newClient.init(clientParams.toBuilder().clearBulletinBoardAddress().addBulletinBoardAddress(address).build()); + + subscriberClients.add(newClient); + + } + + subscriber = new ThreadedBulletinBoardSubscriber(subscriberClients, localClient); + + } + + @Override + public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { + return null; + } + + @Override + public float getRedundancy(MessageID id) { + return 0; + } + + @Override + public List readMessages(MessageFilterList filterList) { + return null; + } + + @Override + public SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException { + return null; + } + + @Override + public void close() { + + } + + @Override + public void subscribe(MessageFilterList filterList, FutureCallback> callback) { + + } + + @Override + public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { + + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java new file mode 100644 index 0000000..df3e196 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -0,0 +1,531 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.*; +import com.google.protobuf.ByteString; +import meerkat.comm.CommunicationException; +import meerkat.comm.MessageInputStream; +import meerkat.comm.MessageInputStream.MessageInputStreamFactory; +import meerkat.comm.MessageOutputStream; +import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Voting.*; +import meerkat.util.BulletinBoardUtils; + +import javax.ws.rs.NotFoundException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Created by Arbel Deutsch Peled on 15-Mar-16. + * This client is to be used mainly for testing. + * It wraps a BulletinBoardServer in an asynchronous client. + * This means the access to the server is direct (via method calls) instead of through a TCP connection. + * The client implements both synchronous and asynchronous method calls, but calls to the server itself are performed synchronously. + */ +public class LocalBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient{ + + private final BulletinBoardServer server; + private final ListeningScheduledExecutorService executorService; + private final BatchDigest digest; + private final int subsrciptionDelay; + + /** + * Initializes an instance of the client + * @param server an initialized Bulletin Board Server instance which will perform the actual processing of the requests + * @param threadNum is the number of concurrent threads to allocate for the client + * @param subscriptionDelay is the required delay between subscription calls in milliseconds + */ + public LocalBulletinBoardClient(BulletinBoardServer server, int threadNum, int subscriptionDelay) { + this.server = server; + this.executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadNum)); + this.digest = new GenericBatchDigest(new SHA256Digest()); + this.subsrciptionDelay = subscriptionDelay; + } + + private class MessagePoster implements Callable { + + private final BulletinBoardMessage msg; + + public MessagePoster(BulletinBoardMessage msg) { + this.msg = msg; + } + + + @Override + public Boolean call() throws Exception { + return server.postMessage(msg).getValue(); + } + + } + + @Override + public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback) { + + Futures.addCallback(executorService.submit(new MessagePoster(msg)), callback); + + digest.update(msg.getMsg()); + return digest.digestAsMessageID(); + + } + + private class CompleteBatchPoster implements Callable { + + private final CompleteBatch completeBatch; + + public CompleteBatchPoster(CompleteBatch completeBatch) { + this.completeBatch = completeBatch; + } + + + @Override + public Boolean call() throws Exception { + + if (!server.beginBatch(completeBatch.getBeginBatchMessage()).getValue()) + return false; + + int i=0; + for (BatchData data : completeBatch.getBatchDataList()){ + + BatchMessage message = BatchMessage.newBuilder() + .setSignerId(completeBatch.getSignature().getSignerId()) + .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) + .setSerialNum(i) + .setData(data) + .build(); + + if (!server.postBatchMessage(message).getValue()) + return false; + + i++; + } + + return server.closeBatchMessage(completeBatch.getCloseBatchMessage()).getValue(); + } + + } + + @Override + public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { + + Futures.addCallback(executorService.schedule(new CompleteBatchPoster(completeBatch), subsrciptionDelay, TimeUnit.MILLISECONDS), callback); + + digest.update(completeBatch); + return digest.digestAsMessageID(); + + } + + private class BatchBeginner implements Callable { + + private final BeginBatchMessage msg; + + public BatchBeginner(BeginBatchMessage msg) { + this.msg = msg; + } + + + @Override + public Boolean call() throws Exception { + return server.beginBatch(msg).getValue(); + } + + } + + @Override + public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + Futures.addCallback(executorService.submit(new BatchBeginner(beginBatchMessage)), callback); + } + + private class BatchDataPoster implements Callable { + + private final ByteString signerId; + private final int batchId; + private final List batchDataList; + private final int startPosition; + + public BatchDataPoster(ByteString signerId, int batchId, List batchDataList, int startPosition) { + this.signerId = signerId; + this.batchId = batchId; + this.batchDataList = batchDataList; + this.startPosition = startPosition; + } + + + @Override + public Boolean call() throws Exception { + + BatchMessage.Builder msgBuilder = BatchMessage.newBuilder() + .setSignerId(signerId) + .setBatchId(batchId); + + int i = startPosition; + for (BatchData data : batchDataList){ + + msgBuilder.setSerialNum(i) + .setData(data); + + if (!server.postBatchMessage(msgBuilder.build()).getValue()) + return false; + + i++; + + } + + return true; + + } + + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + postBatchData(ByteString.copyFrom(signerId), batchId, batchDataList, startPosition, callback); + } + + @Override + public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback) { + postBatchData(signerId, batchId, batchDataList, 0, callback); + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + Futures.addCallback(executorService.submit(new BatchDataPoster(signerId, batchId, batchDataList, startPosition)), callback); + } + + @Override + public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback) { + postBatchData(signerId, batchId, batchDataList, 0, callback); + } + + private class BatchCloser implements Callable { + + private final CloseBatchMessage msg; + + public BatchCloser(CloseBatchMessage msg) { + this.msg = msg; + } + + + @Override + public Boolean call() throws Exception { + return server.closeBatchMessage(msg).getValue(); + } + + } + + @Override + public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + Futures.addCallback(executorService.submit(new BatchCloser(closeBatchMessage)), callback); + } + + private class RedundancyGetter implements Callable { + + private final MessageID msgId; + + public RedundancyGetter(MessageID msgId) { + this.msgId = msgId; + } + + + @Override + public Float call() throws Exception { + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(msgId.getID()) + .build()) + .build(); + + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream outputStream = new MessageOutputStream<>(byteOutputStream); + server.readMessages(filterList,outputStream); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BulletinBoardMessage.class); + + if (inputStream.isAvailable()) + return 1.0f; + else + return 0.0f; + + } + + } + + @Override + public void getRedundancy(MessageID id, FutureCallback callback) { + Futures.addCallback(executorService.submit(new RedundancyGetter(id)), callback); + } + + private class MessageReader implements Callable> { + + private final MessageFilterList filterList; + + public MessageReader(MessageFilterList filterList) { + this.filterList = filterList; + } + + + @Override + public List call() throws Exception { + + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream outputStream = new MessageOutputStream<>(byteOutputStream); + server.readMessages(filterList, outputStream); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BulletinBoardMessage.class); + + return inputStream.asList(); + + } + + } + + @Override + public void readMessages(MessageFilterList filterList, FutureCallback> callback) { + Futures.addCallback(executorService.submit(new MessageReader(filterList)), callback); + } + + class SubscriptionCallback implements FutureCallback> { + + private MessageFilterList filterList; + private final FutureCallback> callback; + + public SubscriptionCallback(MessageFilterList filterList, FutureCallback> callback) { + this.filterList = filterList; + this.callback = callback; + } + + @Override + public void onSuccess(List result) { + + // Report new messages to user + callback.onSuccess(result); + + MessageFilterList.Builder filterBuilder = filterList.toBuilder(); + + // If any new messages arrived: update the MIN_ENTRY condition + if (result.size() > 0) { + + // Remove last filter from list (MIN_ENTRY one) + filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); + + // Add updated MIN_ENTRY filter (entry number is successor of last received entry's number) + filterBuilder.addFilter(MessageFilter.newBuilder() + .setType(FilterType.MIN_ENTRY) + .setEntry(result.get(result.size() - 1).getEntryNum() + 1) + .build()); + + } + + filterList = filterBuilder.build(); + + // Reschedule job + Futures.addCallback(executorService.submit(new MessageReader(filterList)), this); + + } + + @Override + public void onFailure(Throwable t) { + + // Notify caller about failure and terminate subscription + callback.onFailure(t); + + } + } + + @Override + public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { + + MessageFilterList subscriptionFilterList = + filterList.toBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MIN_ENTRY) + .setEntry(startEntry) + .build()) + .build(); + + Futures.addCallback(executorService.submit(new MessageReader(subscriptionFilterList)), new SubscriptionCallback(subscriptionFilterList, callback)); + + } + + @Override + public void subscribe(MessageFilterList filterList, FutureCallback> callback) { + subscribe(filterList, 0, callback); + } + + private class CompleteBatchReader implements Callable { + + private final BatchSpecificationMessage batchSpecificationMessage; + + public CompleteBatchReader(BatchSpecificationMessage batchSpecificationMessage) { + this.batchSpecificationMessage = batchSpecificationMessage; + } + + + @Override + public CompleteBatch call() throws Exception { + + final String[] TAGS_TO_REMOVE = {BulletinBoardConstants.BATCH_TAG, BulletinBoardConstants.BATCH_ID_TAG_PREFIX}; + + CompleteBatch completeBatch = new CompleteBatch(BeginBatchMessage.newBuilder() + .setSignerId(batchSpecificationMessage.getSignerId()) + .setBatchId(batchSpecificationMessage.getBatchId()) + .build()); + + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream batchOutputStream = new MessageOutputStream<>(byteOutputStream); + server.readBatch(batchSpecificationMessage,batchOutputStream); + + MessageInputStream batchInputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BatchData.class); + + completeBatch.appendBatchData(batchInputStream.asList()); + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_TAG) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + completeBatch.getBeginBatchMessage().getBatchId()) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(completeBatch.getBeginBatchMessage().getSignerId()) + .build()) + .build(); + + byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream messageOutputStream = new MessageOutputStream<>(byteOutputStream); + server.readMessages(filterList,messageOutputStream); + + MessageInputStream messageInputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BulletinBoardMessage.class); + + if (!messageInputStream.isAvailable()) + throw new NotFoundException("Batch does not exist"); + + BulletinBoardMessage message = messageInputStream.readMessage(); + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .addAllTag(BulletinBoardUtils.removePrefixTags(message, Arrays.asList(TAGS_TO_REMOVE))) + .setSignerId(message.getSig(0).getSignerId()) + .setBatchId(Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX))) + .build()); + + completeBatch.setSignature(message.getSig(0)); + completeBatch.setTimestamp(message.getMsg().getTimestamp()); + + return completeBatch; + + } + + } + + @Override + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + Futures.addCallback(executorService.submit(new CompleteBatchReader(batchSpecificationMessage)), callback); + } + + private class SyncQueryHandler implements Callable { + + private final SyncQuery syncQuery; + + public SyncQueryHandler(SyncQuery syncQuery) { + this.syncQuery = syncQuery; + } + + + @Override + public SyncQueryResponse call() throws Exception { + return server.querySync(syncQuery); + } + + } + + @Override + public void querySync(SyncQuery syncQuery, FutureCallback callback) { + Futures.addCallback(executorService.submit(new SyncQueryHandler(syncQuery)), callback); + } + + /** + * This method is a stub, since the implementation only considers one server, and that is given in the constructor + * @param ignored is ignored + */ + @Override + public void init(BulletinBoardClientParams ignored) {} + + @Override + public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { + + try { + + MessagePoster poster = new MessagePoster(msg); + poster.call(); + + digest.update(msg); + return digest.digestAsMessageID(); + + } catch (Exception e) { + return null; + } + + } + + @Override + public float getRedundancy(MessageID id) { + + try { + + RedundancyGetter getter = new RedundancyGetter(id); + return getter.call(); + + } catch (Exception e) { + return -1.0f; + } + + } + + @Override + public List readMessages(MessageFilterList filterList) { + + try { + + MessageReader reader = new MessageReader(filterList); + return reader.call(); + + } catch (Exception e){ + return null; + } + + } + + @Override + public SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException { + return server.generateSyncQuery(GenerateSyncQueryParams); + } + + @Override + public void close() { + try { + server.close(); + } catch (CommunicationException ignored) {} + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java new file mode 100644 index 0000000..cf8d47d --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java @@ -0,0 +1,272 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.Timestamp; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.util.BulletinBoardUtils; + +import static meerkat.protobuf.BulletinBoardAPI.FilterType.*; + +import java.sql.Time; +import java.util.*; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Created by Arbel Deutsch Peled on 03-Mar-16. + * A multi-server implementation of the {@link BulletinBoardSubscriber} + */ +public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber { + + protected final Collection clients; + protected final BulletinBoardClient localClient; + + protected Iterator clientIterator; + protected SubscriptionAsyncBulletinBoardClient currentClient; + + private long lastServerSwitchTime; + + private AtomicBoolean isSyncInProgress; + private Semaphore rescheduleSemaphore; + + private static final Float[] BREAKPOINTS = {0.5f, 0.75f, 0.9f, 0.95f, 0.99f, 0.999f}; + + public ThreadedBulletinBoardSubscriber(Collection clients, BulletinBoardClient localClient) { + + this.clients = clients; + this.localClient = localClient; + + lastServerSwitchTime = System.currentTimeMillis(); + + clientIterator = clients.iterator(); + currentClient = clientIterator.next(); + + isSyncInProgress = new AtomicBoolean(false); + rescheduleSemaphore = new Semaphore(1); + + } + + /** + * Moves to next client and performs resync with it + */ + private void nextClient() { + + try { + + rescheduleSemaphore.acquire(); + + if (!clientIterator.hasNext()){ + clientIterator = clients.iterator(); + } + + currentClient = clientIterator.next(); + + lastServerSwitchTime = System.currentTimeMillis(); + + isSyncInProgress.set(false); + + rescheduleSemaphore.release(); + + } catch (InterruptedException e) { + // TODO: log + // Do not change client + } + + } + + private abstract class SubscriberCallback implements FutureCallback { + + protected final MessageFilterList filterList; + protected final FutureCallback> callback; + private final long invocationTime; + + public SubscriberCallback(MessageFilterList filterList, FutureCallback> callback) { + + this.filterList = filterList; + this.callback = callback; + this.invocationTime = System.currentTimeMillis(); + + } + + /** + * Handles resyncing process for the given subscription after a server is switched + * Specifically: generates a sync query from the local database and uses it to query the current server + */ + private void reSync() { + + SyncQuery syncQuery = null; + try { + + syncQuery = localClient.generateSyncQuery(GenerateSyncQueryParams.newBuilder() + .setFilterList(filterList) + .addAllBreakpointList(Arrays.asList(BREAKPOINTS)) + .build()); + + } catch (CommunicationException e) { + + // Handle failure in standard way + onFailure(e); + + } + + currentClient.querySync(syncQuery, new SyncQueryCallback(filterList, callback)); + + } + + /** + * Reschedules the subscription + */ + private void reschedule() { + + try { + + rescheduleSemaphore.acquire(); + + reSync(); + + rescheduleSemaphore.release(); + + + } catch (InterruptedException e) { + + //TODO: log + + callback.onFailure(e); // Hard error: Cannot guarantee subscription safety + + } + + } + + @Override + public void onFailure(Throwable t) { + + // If server failure is not already known: switch to next client and resync + if (invocationTime > lastServerSwitchTime){ + + // Make sure only what thread switches the client + if (isSyncInProgress.compareAndSet(false, true)){ + nextClient(); + } + + } + + reschedule(); + + } + + } + + /** + * Provides handling logic for resync query callback operation + * Receives a SyncQueryResponse and reads the missing data (starting from the received timestamp) if needed + */ + protected class SyncQueryCallback extends SubscriberCallback { + + public SyncQueryCallback (MessageFilterList filterList, FutureCallback> callback) { + + super(filterList, callback); + + } + + @Override + public void onSuccess(SyncQueryResponse result) { + + final Timestamp DEFAULT_TIME = BulletinBoardUtils.toTimestampProto(946728000); // Year 2000 + + // Read required messages according to received Timestamp + + Timestamp syncTimestamp; + + if (result.hasLastTimeOfSync()) { + syncTimestamp = result.getLastTimeOfSync(); // Use returned time of sync + } else { + syncTimestamp = DEFAULT_TIME; // Get all messages + } + + MessageFilterList timestampedFilterList = filterList.toBuilder() + .removeFilter(filterList.getFilterCount()-1) // Remove MIN_ENTRY filter + .addFilter(MessageFilter.newBuilder() // Add timestamp filter + .setType(AFTER_TIME) + .setTimestamp(syncTimestamp) + .build()) + .build(); + + currentClient.readMessages(timestampedFilterList, new ReSyncCallback(filterList, callback, result.getLastEntryNum())); + + } + + } + + /** + * Provides handling logic for callback of resyncing process + * Receives the missing messages, handles them and resubscribes + */ + protected class ReSyncCallback extends SubscriberCallback> { + + private long minEntry; + + public ReSyncCallback (MessageFilterList filterList, FutureCallback> callback, long minEntry) { + + super(filterList, callback); + + this.minEntry = minEntry; + + } + + @Override + public void onSuccess(List result) { + + // Propagate result to caller + callback.onSuccess(result); + + // Renew subscription + + MessageFilterList newFilterList = filterList.toBuilder() + .removeFilter(filterList.getFilterCount()-1) // Remove current MIN_ENTRY filter + .addFilter(MessageFilter.newBuilder() // Add new MIN_ENTRY filter for current server + .setType(MIN_ENTRY) + .setEntry(minEntry) + .build()) + .build(); + + currentClient.subscribe(newFilterList, callback); + + } + + } + + /** + * Provides the handling logic for results and failures of main subscription (while there are no errors) + */ + protected class SubscriptionCallback extends SubscriberCallback> { + + public SubscriptionCallback(MessageFilterList filterList, FutureCallback> callback){ + super(filterList, callback); + } + + + @Override + public void onSuccess(List result) { + + // Propagate result to caller + callback.onSuccess(result); + + } + + } + + @Override + public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { + + currentClient.subscribe(filterList, startEntry, new SubscriptionCallback(filterList, callback)); + + } + + @Override + public void subscribe(MessageFilterList filterList, FutureCallback> callback) { + subscribe(filterList, 0, callback); + } + + +} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java new file mode 100644 index 0000000..88fb22c --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java @@ -0,0 +1,519 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; +import meerkat.comm.CommunicationException; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; +import meerkat.util.BulletinBoardMessageComparator; +import meerkat.util.BulletinBoardMessageGenerator; + +import java.io.IOException; +import java.io.InputStream; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.*; +import java.util.concurrent.Semaphore; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo; +import static org.junit.Assert.*; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class GenericBulletinBoardClientTester { + + // Signature resources + + private GenericBatchDigitalSignature signers[]; + private ByteString[] signerIDs; + + private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12"; + + private static String KEYFILE_PASSWORD1 = "secret"; + private static String KEYFILE_PASSWORD3 = "shh"; + + private static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + private static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; + + // Client and callbacks + + private AsyncBulletinBoardClient bulletinBoardClient; + + private PostCallback postCallback; + private PostCallback failPostCallback = new PostCallback(true,false); + + private RedundancyCallback redundancyCallback; + private ReadCallback readCallback; + private ReadBatchCallback readBatchCallback; + + // Sync and misc + + private Semaphore jobSemaphore; + private Vector thrown; + private Random random; + + // Constructor + + public GenericBulletinBoardClientTester(AsyncBulletinBoardClient bulletinBoardClient){ + + this.bulletinBoardClient = bulletinBoardClient; + + signers = new GenericBatchDigitalSignature[2]; + signerIDs = new ByteString[signers.length]; + signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); + + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD1.toCharArray(); + + KeyStore.Builder keyStoreBuilder; + try { + keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); + + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); + password = KEYFILE_PASSWORD3.toCharArray(); + + keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); + signers[1].loadSigningCertificate(keyStoreBuilder); + + signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + + for (int i = 0 ; i < signers.length ; i++) { + signerIDs[i] = signers[i].getSignerID(); + } + + } catch (IOException e) { + System.err.println("Failed reading from signature file " + e.getMessage()); + fail("Failed reading from signature file " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("Failed reading certificate " + e.getMessage()); + fail("Failed reading certificate " + e.getMessage()); + } catch (KeyStoreException e) { + System.err.println("Failed reading keystore " + e.getMessage()); + fail("Failed reading keystore " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.err.println("Couldn't find signing algorithm " + e.getMessage()); + fail("Couldn't find signing algorithm " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + System.err.println("Couldn't find signing key " + e.getMessage()); + fail("Couldn't find signing key " + e.getMessage()); + } + + } + + // Callback definitions + + protected void genericHandleFailure(Throwable t){ + System.err.println(t.getCause() + " " + t.getMessage()); + thrown.add(t); + jobSemaphore.release(); + } + + private class PostCallback implements FutureCallback{ + + private boolean isAssert; + private boolean assertValue; + + public PostCallback() { + this(false); + } + + public PostCallback(boolean isAssert) { + this(isAssert,true); + } + + public PostCallback(boolean isAssert, boolean assertValue) { + this.isAssert = isAssert; + this.assertValue = assertValue; + } + + @Override + public void onSuccess(Boolean msg) { + System.err.println("Post operation completed"); + jobSemaphore.release(); + //TODO: Change Assert mechanism to exception one + if (isAssert) { + if (assertValue) { + assertThat("Post operation failed", msg, is(Boolean.TRUE)); + } else { + assertThat("Post operation succeeded unexpectedly", msg, is(Boolean.FALSE)); + } + } + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class RedundancyCallback implements FutureCallback{ + + private float minRedundancy; + + public RedundancyCallback(float minRedundancy) { + this.minRedundancy = minRedundancy; + } + + @Override + public void onSuccess(Float redundancy) { + System.err.println("Redundancy found is: " + redundancy); + jobSemaphore.release(); + assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class ReadCallback implements FutureCallback>{ + + private List expectedMsgList; + + public ReadCallback(List expectedMsgList) { + this.expectedMsgList = expectedMsgList; + } + + @Override + public void onSuccess(List messages) { + + System.err.println(messages); + jobSemaphore.release(); + + BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); + + assertThat(messages.size(), is(expectedMsgList.size())); + + Iterator expectedMessageIterator = expectedMsgList.iterator(); + Iterator receivedMessageIterator = messages.iterator(); + + while (expectedMessageIterator.hasNext()) { + assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); + } + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + private class ReadBatchCallback implements FutureCallback { + + private CompleteBatch expectedBatch; + + public ReadBatchCallback(CompleteBatch expectedBatch) { + this.expectedBatch = expectedBatch; + } + + @Override + public void onSuccess(CompleteBatch batch) { + + System.err.println(batch); + jobSemaphore.release(); + + assertThat("Batch returned is incorrect", batch, is(equalTo(expectedBatch))); + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + } + + // Randomness generators + + private byte randomByte(){ + return (byte) random.nextInt(); + } + + private byte[] randomByteArray(int length) { + + byte[] randomBytes = new byte[length]; + + for (int i = 0; i < length ; i++){ + randomBytes[i] = randomByte(); + } + + return randomBytes; + + } + + private CompleteBatch createRandomBatch(int signer, int batchId, int length) throws SignatureException { + + CompleteBatch completeBatch = new CompleteBatch(); + + // Create data + + completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() + .setSignerId(signerIDs[signer]) + .setBatchId(batchId) + .addTag("Test") + .build()); + + for (int i = 0 ; i < length ; i++){ + + BatchData batchData = BatchData.newBuilder() + .setData(ByteString.copyFrom(randomByteArray(i))) + .build(); + + completeBatch.appendBatchData(batchData); + + } + + completeBatch.setTimestamp(Timestamp.newBuilder() + .setSeconds(Math.abs(90)) + .setNanos(50) + .build()); + + signers[signer].updateContent(completeBatch); + + completeBatch.setSignature(signers[signer].sign()); + + return completeBatch; + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + public void init(){ + + random = new Random(0); // We use insecure randomness in tests for repeatability + + postCallback = new PostCallback(); + redundancyCallback = new RedundancyCallback((float) 1.0); + + thrown = new Vector<>(); + jobSemaphore = new Semaphore(0); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + public void close() { + + if (thrown.size() > 0) { + assert false; + } + + } + + /** + * Tests the standard post, redundancy and read methods + */ + public void postTest() { + + 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}; + + BulletinBoardMessage msg; + + MessageFilterList filterList; + List msgList; + + MessageID messageID; + + msg = BulletinBoardMessage.newBuilder() + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .addTag("Signature") + .addTag("Trustee") + .setData(ByteString.copyFrom(b1)) + .setTimestamp(Timestamp.newBuilder() + .setSeconds(20) + .setNanos(30) + .build()) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.DSA) + .setData(ByteString.copyFrom(b2)) + .setSignerId(ByteString.copyFrom(b3)) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.ECDSA) + .setData(ByteString.copyFrom(b3)) + .setSignerId(ByteString.copyFrom(b2)) + .build()) + .build(); + + messageID = bulletinBoardClient.postMessage(msg,postCallback); + + try { + jobSemaphore.acquire(); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + bulletinBoardClient.getRedundancy(messageID,redundancyCallback); + + filterList = MessageFilterList.newBuilder() + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Signature") + .build() + ) + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Trustee") + .build() + ) + .build(); + + msgList = new LinkedList<>(); + msgList.add(msg); + + readCallback = new ReadCallback(msgList); + + bulletinBoardClient.readMessages(filterList, readCallback); + try { + jobSemaphore.acquire(2); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + } + + /** + * Tests posting a batch by parts + * Also tests not being able to post to a closed batch + * @throws CommunicationException, SignatureException, InterruptedException + */ + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + final int SIGNER = 1; + final int BATCH_ID = 100; + final int BATCH_LENGTH = 100; + + CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); + + // Begin batch + + bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), postCallback); + + jobSemaphore.acquire(); + + // Post data + + bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), postCallback); + + jobSemaphore.acquire(); + + // Close batch + + CloseBatchMessage closeBatchMessage = completeBatch.getCloseBatchMessage(); + + bulletinBoardClient.closeBatch(closeBatchMessage, postCallback); + + jobSemaphore.acquire(); + + // Attempt to open batch again + + bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), failPostCallback); + + // Attempt to add batch data + + bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), failPostCallback); + + jobSemaphore.acquire(2); + + // Read batch data + + BatchSpecificationMessage batchSpecificationMessage = + BatchSpecificationMessage.newBuilder() + .setSignerId(signerIDs[SIGNER]) + .setBatchId(BATCH_ID) + .setStartPosition(0) + .build(); + + readBatchCallback = new ReadBatchCallback(completeBatch); + + bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + + jobSemaphore.acquire(); + + } + + /** + * Posts a complete batch message + * Checks reading of the message + * @throws CommunicationException, SignatureException, InterruptedException + */ + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + final int SIGNER = 0; + final int BATCH_ID = 101; + final int BATCH_LENGTH = 50; + + // Post batch + + CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); + + bulletinBoardClient.postBatch(completeBatch,postCallback); + + jobSemaphore.acquire(); + + // Read batch + + BatchSpecificationMessage batchSpecificationMessage = + BatchSpecificationMessage.newBuilder() + .setSignerId(signerIDs[SIGNER]) + .setBatchId(BATCH_ID) + .setStartPosition(0) + .build(); + + readBatchCallback = new ReadBatchCallback(completeBatch); + + bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + + jobSemaphore.acquire(); + + } + + /** + * Tests that an unopened batch cannot be closed + * @throws CommunicationException, InterruptedException + */ + public void testInvalidBatchClose() throws CommunicationException, InterruptedException { + + final int NON_EXISTENT_BATCH_ID = 999; + + CloseBatchMessage closeBatchMessage = + CloseBatchMessage.newBuilder() + .setBatchId(NON_EXISTENT_BATCH_ID) + .setBatchLength(1) + .setSig(Crypto.Signature.getDefaultInstance()) + .setTimestamp(Timestamp.newBuilder() + .setSeconds(9) + .setNanos(12) + .build()) + .build(); + + // Try to close the (unopened) batch; + + bulletinBoardClient.closeBatch(closeBatchMessage, failPostCallback); + + jobSemaphore.acquire(); + + } + +} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java new file mode 100644 index 0000000..b69cf72 --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java @@ -0,0 +1,95 @@ +package meerkat.bulletinboard; + +import meerkat.comm.CommunicationException; + +import meerkat.protobuf.Voting.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.security.SignatureException; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class ThreadedBulletinBoardClientIntegrationTest { + + // Server data + + 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); + + // Tester + private GenericBulletinBoardClientTester clientTest; + + public ThreadedBulletinBoardClientIntegrationTest(){ + + ThreadedBulletinBoardClient client = new ThreadedBulletinBoardClient(); + + List testDB = new LinkedList<>(); + testDB.add(BASE_URL); + + client.init(BulletinBoardClientParams.newBuilder() + .addAllBulletinBoardAddress(testDB) + .setMinRedundancy((float) 1.0) + .build()); + + clientTest = new GenericBulletinBoardClientTester(client); + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + @Before + public void init(){ + + clientTest.init(); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + @After + public void close() { + + clientTest.close(); + + } + + @Test + public void postTest() { + + clientTest.postTest(); + + } + + @Test + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testBatchPost(); + } + + @Test + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testCompleteBatchPost(); + + } + + @Test + public void testInvalidBatchClose() throws CommunicationException, InterruptedException { + + clientTest.testInvalidBatchClose(); + + } + +} From 5670739e494d78a2de14ff80bba8e5a6b9bbe899 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Wed, 30 Mar 2016 12:44:04 +0300 Subject: [PATCH 034/106] tested version --- .../src/main/java/Arithmetics/Fp.java | 27 +-- .../java/Communication/MessageHandler.java | 2 +- .../src/main/java/Communication/Network.java | 2 +- .../VerifiableSecretSharing.java | 5 +- .../DistributedKeyGeneration.java | 70 +++--- .../DistributedKeyGenerationParty.java | 9 +- .../DistributedKeyGenerationUserImpl.java | 221 +++++++++++------- .../SecureDistributedKeyGeneration.java | 78 ++++--- ...reDistributedKeyGenerationMailHandler.java | 2 +- .../SecureDistributedKeyGenerationParty.java | 8 +- ...ecureDistributedKeyGenerationUserImpl.java | 142 +++++++---- .../LagrangePolynomial.java | 18 +- .../java/ShamirSecretSharing/Polynomial.java | 27 +-- .../ShamirSecretSharing/SecretSharing.java | 4 +- .../JointFeldmanProtocol/DKGDeepTest.java | 174 -------------- .../DKGMaliciousUserImpl.java | 36 +-- .../java/JointFeldmanProtocol/DKGTest.java | 193 +++++++++------ .../SDKGMaliciousUserImpl.java | 64 +++++ .../SDKGTest.java | 191 +++++++++------ .../SDKGUserImplAbort.java | 11 +- .../PolynomialTests/AddTest.java | 6 +- .../PolynomialTests/InterpolationTest.java | 7 +- .../PolynomialTests/MulByConstTest.java | 4 +- .../PolynomialTests/MulTest.java | 6 +- .../SecretSharingTest.java | 3 +- .../GenerateRandomPolynomial.java} | 11 +- .../test/java/Utils/GenerateRandomPrime.java | 32 +++ 27 files changed, 745 insertions(+), 608 deletions(-) delete mode 100644 destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java create mode 100644 destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java rename destributed-key-generation/src/test/java/{ShamirSecretSharing/PolynomialTests/Utils.java => Utils/GenerateRandomPolynomial.java} (75%) create mode 100644 destributed-key-generation/src/test/java/Utils/GenerateRandomPrime.java diff --git a/destributed-key-generation/src/main/java/Arithmetics/Fp.java b/destributed-key-generation/src/main/java/Arithmetics/Fp.java index 545dd8b..db2d6da 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Fp.java +++ b/destributed-key-generation/src/main/java/Arithmetics/Fp.java @@ -1,5 +1,7 @@ package Arithmetics; +import org.factcenter.qilin.primitives.concrete.Zpstar; + import java.math.BigInteger; /** @@ -7,9 +9,11 @@ import java.math.BigInteger; */ public class Fp implements Arithmetic { public final BigInteger p; + private final Zpstar zp; public Fp(BigInteger p) { this.p = p; + this.zp = new Zpstar(p); } @Override @@ -24,30 +28,11 @@ public class Fp implements Arithmetic { @Override public BigInteger mul(BigInteger a,BigInteger b){ - return a.multiply(b).mod(p); + return zp.add(a,b); } @Override public BigInteger div(BigInteger a,BigInteger b){ - return mul(a,inv(b)); - } - - public BigInteger pow(BigInteger b,BigInteger e){ - if (e.compareTo(BigInteger.ZERO) < 0 ) { - return pow(inv(b), e.negate()); - } - BigInteger result = BigInteger.ONE; - while (e.compareTo(BigInteger.ZERO) > 0) { - if (e.testBit(0)) { - result = mul(result, b); - } - e = e.shiftRight(1); - b = mul(b, b); - } - return result; - } - - public BigInteger inv(BigInteger a){ - return pow(a,p.subtract(BigInteger.valueOf(2))); + return mul(a,zp.negate(b)); } } diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/Communication/MessageHandler.java index 2d68be4..8cedf4e 100644 --- a/destributed-key-generation/src/main/java/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MessageHandler.java @@ -9,7 +9,7 @@ public interface MessageHandler { void handelSecretMessage(int sender, boolean isBroadcast, Message message); void handelCommitmentMessage(int sender, boolean isBroadcast, Message message); void handelComplaintMessage(int sender, boolean isBroadcast, Message message); - void handelDoneMessage(int sender, boolean isBroadcast, Message message); //will be remove + void handelDoneMessage(int sender, boolean isBroadcast, Message message); void handelAnswerMessage(int sender, boolean isBroadcast, Message message); void handelAbortMessage(int sender, boolean isBroadcast, Message message); } diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java index ca53991..541179e 100644 --- a/destributed-key-generation/src/main/java/Communication/Network.java +++ b/destributed-key-generation/src/main/java/Communication/Network.java @@ -10,7 +10,7 @@ import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; /** * Created by Tzlil on 2/7/2016. - * JointFeldamn protocol assumes all parties can communicate throw broadcast chanel + * Joint Feldamn protocol assumes all parties can communicate throw broadcast chanel * and private chanel (for each pair) * this class simulates it */ diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 521714d..4573c57 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -3,11 +3,8 @@ package FeldmanVerifiableSecretSharing; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; -import java.util.Arrays; - import org.factcenter.qilin.primitives.Group; -import org.factcenter.qilin.primitives.concrete.Zpstar; - +import java.util.Arrays; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java index 99feec6..d9ae852 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -17,7 +17,7 @@ import java.util.Set; * Created by Tzlil on 3/14/2016. */ public class DistributedKeyGeneration extends VerifiableSecretSharing { - public enum ComplainState{ + public enum ComplaintState { Non, Waiting,Disqualified,NonDisqualified } protected final int id; @@ -32,6 +32,7 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { for (int i = 1; i <= n ; i++){ this.parties[i - 1] = new DistributedKeyGenerationParty(i,n,t); } + this.parties[id - 1].share = getShare(id); } protected void setParties(DistributedKeyGenerationParty[] parties){ @@ -87,9 +88,21 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { return isValidSecret(party.share,party.commitments,id); } + /** + * + * @param secret + * @param commitments + * @param j + * @return verify(j,commitments,group) == g ^ secret.y mod q + */ public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ - BigInteger v = verify(j,commitments,group); - return group.multiply(g,secret.y).equals(v); + try{ + BigInteger v = verify(j,commitments,group); + return group.multiply(g,secret.y).equals(v); + } + catch (NullPointerException e){ + return false; + } } /** @@ -97,27 +110,22 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { * Pj verifies all the shares he received (using isValidSecret) * if check fails for an index i, Pj broadcasts a complaint against Pi. */ - public void broadcastComplains(User user){ - DKGMessages.IDMessage complaint; + public void broadcastComplaints(User user){ for (int i = 1; i <= n ; i++ ){ - if(i != id && !parties[i - 1].aborted) { - sendComplain(user,i); + if(i != id && !isValidSecret(i)) { + broadcastComplaint(user,i); } } } - protected void sendComplain(User user,int i){ - DKGMessages.IDMessage complaint; - if (!isValidSecret(i)) { - //message = new Message(Type.Complaint, j) - complaint = DKGMessages.IDMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); - } + private void broadcastComplaint(User user, int i){ + //message = new Message(Type.Complaint, j) + DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() + .setId(i) + .build(); + user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); } - public void broadcastComplaintAnswer(User user, int j){ user.broadcast(DKGMessages.Mail.Type.ANSWER, DKGMessages.SecretMessage.newBuilder() .setI(id) @@ -131,9 +139,9 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { * if more than t players complain against a player Pi he is disqualified. */ public void answerAllComplainingPlayers(User user){ - ComplainState[] complains = parties[id - 1].complaints; + ComplaintState[] complaints = parties[id - 1].complaints; for (int i = 1; i <= n ; i++) { - switch (complains[i - 1]) { + switch (complaints[i - 1]) { case Waiting: broadcastComplaintAnswer(user,i); break; @@ -143,20 +151,6 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { } } - protected boolean isPartyCompletedStage1(int i){ - if(parties[i - 1].aborted){ - if(parties[i - 1].share == null){ - return false; - } - for (int k = 0; k <= t ; k++){ - if(parties[i - 1].commitments[k] == null){ - return false; - } - } - } - return true; - } - /** * stage3.2 according to the protocol * if any of the revealed shares fails the verification test, player Pi is disqualified. @@ -167,11 +161,11 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { boolean nonDisqualified; int counter; for (int i = 1; i <= n; i++){ - ComplainState[] complains = parties[i - 1].complaints; + ComplaintState[] complaints = parties[i - 1].complaints; nonDisqualified = true; counter = 0; for (int j = 1; j <= n; j++){ - switch (complains[j - 1]) { + switch (complaints[j - 1]) { case Non: break; case NonDisqualified: @@ -182,7 +176,7 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { if(!nonDisqualified) break; } - if(nonDisqualified && counter <= t && isPartyCompletedStage1(i)){ + if(nonDisqualified && counter <= t){ QUAL.add(i); } } @@ -228,6 +222,10 @@ public class DistributedKeyGeneration extends VerifiableSecretSharing { return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } + /** + * getter + * @return id + */ public int getId() { return id; } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java index 617ea08..878ab66 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java @@ -7,21 +7,24 @@ 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 DistributedKeyGenerationParty { public final int id; public Polynomial.Point share; public BigInteger[] commitments; public boolean doneFlag; - public DistributedKeyGeneration.ComplainState[] complaints; + public DistributedKeyGeneration.ComplaintState[] complaints; public boolean aborted; public DistributedKeyGenerationParty(int id, int n, int t) { this.id = id; this.share = null; this.doneFlag = false; - this.complaints = new DistributedKeyGeneration.ComplainState[n]; - Arrays.fill(this.complaints, DistributedKeyGeneration.ComplainState.Non); + this.complaints = new DistributedKeyGeneration.ComplaintState[n]; + Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.Non); this.commitments = new BigInteger[t + 1]; this.aborted = false; } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java index 578b1e5..6287526 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -13,13 +13,15 @@ import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; import java.util.Arrays; import java.util.Set; -import JointFeldmanProtocol.DistributedKeyGeneration.ComplainState; +import JointFeldmanProtocol.DistributedKeyGeneration.ComplaintState; /** * Created by Tzlil on 3/14/2016. */ public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { + protected final static int SleepTime = 300; + protected final DistributedKeyGeneration dkg; protected final BigInteger g; @@ -52,9 +54,6 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio mailHandler.setMessageHandler(this.messageHandler); this.user = network.connect(mailHandler,dkg.getId()); this.parties = dkg.getParties(); - - this.parties[id - 1].share = dkg.getShare(id); - this.QUAL = null; this.commitments = null; this.share = null; @@ -71,6 +70,31 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio dkg.sendSecrets(user); } + protected void waitUntilStageOneCompleted(){ + // all parties send their share or aborted + for (int i = 0 ; i < n ; i++){ + while (parties[i].share == null && !parties[i].aborted){ + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + // all parties broadcast their commitments or aborted + for (int i = 0 ; i < n ; i++){ + for (int k = 0 ; k <= t ; k++) { + while (parties[i].commitments[k] == null && !parties[i].aborted) { + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + } + /** * stage2 according to the protocol * Pj verifies all the shares he received @@ -78,18 +102,26 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio * Pj broadcasts done message at the end of this stage */ protected void stage2(){ - Polynomial.Point[] shares = new Polynomial.Point[n]; - BigInteger[][] commitmentsTable = new BigInteger[n][]; - for (int i = 0 ; i < n ; i++){ - shares[i] = parties[i].share; - commitmentsTable[i] = parties[i].commitments; - } - dkg.broadcastComplains(user); + dkg.broadcastComplaints(user); //broadcast done message after all complaints DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); } + + protected void waitUntilStageTwoCompleted(){ + // all parties done or aborted + for (int i = 0 ; i < n ; i++){ + while (!parties[i].doneFlag && !parties[i].aborted){ + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + /** * stage3 according to the protocol * 1. if more than t players complain against a player Pi he is disqualified. @@ -99,13 +131,12 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio */ protected void stage3(){ dkg.answerAllComplainingPlayers(user); - // wait until there is no complaint waiting for answer for (int i = 0; i < n; i++){ for (int j = 0; j < n; j++){ - while (parties[i].complaints[j].equals(ComplainState.Waiting) && !parties[i].aborted){ + while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted){ try { - Thread.sleep(300); + Thread.sleep(SleepTime); } catch (InterruptedException e) { // do nothing } @@ -127,49 +158,23 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio this.share = dkg.calcShare(QUAL); } - protected void endOfStage1(){ - for (int i = 0 ; i < n ; i++){ - while (parties[i].share == null && !parties[i].aborted){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - - for (int i = 0 ; i < n ; i++){ - for (int k = 0 ; k <= t ; k++) { - while (parties[i].commitments[k] == null && !parties[i].aborted) { - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - } + protected void startReceiver(){ + user.getReceiverThread().start(); + } + protected void stopReceiver(){ + user.getReceiverThread().interrupt(); } @Override public void run() { - user.getReceiverThread().start(); + startReceiver(); stage1(); - endOfStage1(); + waitUntilStageOneCompleted(); stage2(); - for (int i = 0 ; i < n ; i++){ - while (!parties[i].doneFlag && !parties[i].aborted){ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - // do nothing - } - } - } - + waitUntilStageTwoCompleted(); stage3(); stage4(); - user.getReceiverThread().interrupt(); + stopReceiver(); } @Override @@ -217,40 +222,23 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio return QUAL; } + protected class MessageHandler implements Communication.MessageHandler{ - protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKGMessages.IDMessage complaintMessage){ - int i = sender; - int j = complaintMessage.getId(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplainState.Non); - } - - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - parties[j - 1].complaints[i - 1] = ComplainState.Waiting; - } - } - - protected boolean isValidDoneMessage(int sender, boolean isBroadcast){ - return isBroadcast && !parties[sender - 1].doneFlag; - } - - @Override - public void handelDoneMessage(int sender, boolean isBroadcast,Message message) { - if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].doneFlag = true; - } - } + /** + * 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, DKGMessages.CommitmentMessage commitmentMessage){ int i = sender - 1; int k = commitmentMessage.getK(); return isBroadcast && parties[i].commitments[k] == null; } + /** + * saves the commitment + */ @Override public void handelCommitmentMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; @@ -261,6 +249,13 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio } } + /** + * 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, DKGMessages.SecretMessage secretMessage){ int i = secretMessage.getI(); int j = secretMessage.getJ(); @@ -271,6 +266,9 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio } + /** + * saves the secret + */ @Override public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; @@ -281,15 +279,70 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio } } + /** + * 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; + } + + /** + * marks that the sender was finished sending all his complaints + */ + @Override + public void handelDoneMessage(int sender, boolean isBroadcast,Message message) { + if(isValidDoneMessage(sender,isBroadcast)) { + parties[sender - 1].doneFlag = true; + } + } + + /** + * 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, DKGMessages.IDMessage complaintMessage){ + int i = sender; + int j = complaintMessage.getId(); + return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.Non); + } + + /** + * marks that the sender was complained against id + */ + @Override + public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; + } + } + + /** + * 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, DKGMessages.SecretMessage 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(ComplainState.Waiting); + return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(ComplaintState.Waiting); } + /** + * 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 + */ @Override public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; @@ -297,13 +350,20 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio int i = secretMessage.getI(); int j = secretMessage.getJ(); Polynomial.Point secret = extractSecret(j,secretMessage.getSecret()); - if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) - parties[i - 1].complaints[j - 1] = ComplainState.NonDisqualified; - else - parties[i - 1].complaints[j - 1] = ComplainState.Disqualified; + if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) { + parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; + } else { + parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; + } + if(j == id){ + parties[i - 1].share = secret; + } } } + /** + * marks that the sender was aborted + */ @Override public void handelAbortMessage(int sender, boolean isBroadcast, Message message) { parties[sender - 1].aborted = true; @@ -314,6 +374,7 @@ public class DistributedKeyGenerationUserImpl implements DistributedKeyGeneratio BigInteger y = new BigInteger(secret.toByteArray()); return new Polynomial.Point(x,y); } + public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ return new BigInteger(commitmentMessage.getCommitment().toByteArray()); } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java index 4a05125..92c29f3 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java @@ -10,6 +10,7 @@ import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; import java.util.Random; +import java.util.Set; /** * Created by Tzlil on 3/16/2016. @@ -30,28 +31,21 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { for (int i = 1; i <= n ; i++){ this.parties[i - 1] = new SecureDistributedKeyGenerationParty(i,n,t); } - setParties(parties); + this.parties[id - 1].share = getShare(id); + this.parties[id - 1].shareT = verifiableSecretSharing.getShare(id); + super.setParties(parties); } protected SecureDistributedKeyGenerationParty[] getParties(){ return parties; } - @Override - protected boolean isPartyCompletedStage1(int i){ - if(parties[i - 1].aborted){ - if(parties[i - 1].share == null){ - return false; - } - for (int k = 0; k <= t ; k++){ - if(parties[i - 1].verifiableValues[k] == null){ - return false; - } - } - } - return true; + protected void setParties(SecureDistributedKeyGenerationParty[] parties) { + super.setParties(parties); + this.parties = parties; } + @Override public void sendSecret(User user, int j) { Polynomial.Point secret = getShare(j); @@ -60,49 +54,52 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { user.send(j, DKGMessages.Mail.Type.SECRET, doubleSecretMessage); } + @Override public boolean isValidSecret(int i){ SecureDistributedKeyGenerationParty party = parties[i - 1]; - return isValidSecret(party.share,party.shareT,party.verifiableValues, id); + return isValidSecret(party.share, party.shareT, party.verifiableValues, id); } + /** + * @param secret + * @param secretT + * @param verificationValues + * @param j + * @return verify(j,verificationValues,group) == (g ^ secret.y) * (h ^ secretT.y) mod q + */ public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int j){ - BigInteger v = verify(j,verificationValues,group); - BigInteger exp = group.add(group.multiply(g, secret.y),group.multiply(h, secretT.y)); - return exp.equals(v); + try { + BigInteger v = verify(j, verificationValues, group); + BigInteger exp = group.add(group.multiply(g, secret.y), group.multiply(h, secretT.y)); + return exp.equals(v); + } + catch (NullPointerException e){ + return false; + } } - public void broadcastComplaint(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ + private void broadcastComplaint(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); } - public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ - DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); - user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); - } - /** * stage4.3 according to the protocol * if check fails for index i, Pj */ - public void broadcastComplaints(User user, boolean stage4){ - if(!stage4){ - super.broadcastComplains(user); - }else{ - SecureDistributedKeyGenerationParty party; - for (int i = 1; i <= n ; i++ ){ - party = parties[i - 1]; - if(i != id && !party.aborted) { - if (!super.isValidSecret(party.share,party.commitments,id)) { - broadcastComplaint(user,party.share,party.shareT,i); - } + public void broadcastComplaints(User user, Set QUAL){ + SecureDistributedKeyGenerationParty party; + for (int i : QUAL) { + party = parties[i - 1]; + if (i != id) { + if (!super.isValidSecret(party.share, party.commitments, id)) { + broadcastComplaint(user, party.share, party.shareT, i); } } } } - public void broadcastVerificationValues(User user){ BigInteger[] verificationValues = new BigInteger[t + 1]; BigInteger[] hBaseCommitments = verifiableSecretSharing.getCommitmentsArray(); @@ -128,4 +125,13 @@ public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { ,verifiableSecretSharing.getShare(j)); user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); } + + public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ + DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); + user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); + } + + public BigInteger getH() { + return h; + } } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java index bad5d07..9b4752e 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java @@ -30,7 +30,7 @@ public class SecureDistributedKeyGenerationMailHandler extends MailHandler { message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); break; case COMPLAINT: - if(isStage4) + if(!isStage4) message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); else message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java index 3d933a9..ea36136 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java @@ -9,16 +9,20 @@ 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 SecureDistributedKeyGenerationParty extends DistributedKeyGenerationParty { - - public Polynomial.Point shareT; + public boolean ysDoneFlag; public BigInteger[] verifiableValues; public Set restoreSharesSet; public SecureDistributedKeyGenerationParty(int id, int n, int t) { super(id, n, t); this.shareT = null; + this.ysDoneFlag = false; this.verifiableValues = new BigInteger[t + 1]; this.restoreSharesSet = new HashSet(); } diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java index 778a5d2..66751eb 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java @@ -17,9 +17,10 @@ import java.math.BigInteger; */ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { - private final SecureDistributedKeyGeneration sdkg; - private SecureDistributedKeyGenerationParty[] parties; + protected SecureDistributedKeyGenerationParty[] parties; + protected final SecureDistributedKeyGeneration sdkg; private Arithmetic arithmetic; + private boolean isStage4; public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); @@ -28,6 +29,7 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera this.user.setMessageHandler(this.messageHandler); this.parties = sdkg.getParties(); this.arithmetic = new Fp(sdkg.getQ()); + this.isStage4 = false; } /** @@ -42,8 +44,9 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera } @Override - protected void endOfStage1(){ - super.endOfStage1(); + protected void waitUntilStageOneCompleted(){ + super.waitUntilStageOneCompleted(); + // save the received commitments as verification values BigInteger[] temp; for (int i = 0 ; i < n; i++){ temp = parties[i].verifiableValues; @@ -60,54 +63,54 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera */ @Override protected void stage2(){ - sdkg.broadcastComplains(user); + sdkg.broadcastComplaints(user); //broadcast done message after all complaints DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - isVerificationValue = false; user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); } private void ys(){ sdkg.broadcastCommitments(user); - //wait for receive all commitments from all i in QUAL + // wait until all parties in QUAL broadcast their commitments or aborted for (int i:QUAL) { for(int k = 0; k <= t; k++) { while (parties[i - 1].commitments[k] == null && !parties[i - 1].aborted) { try { - Thread.sleep(300); + Thread.sleep(SleepTime); } catch (InterruptedException e) { // do nothing } } } } - sdkg.broadcastComplaints(user,true); + sdkg.broadcastComplaints(user,QUAL); //broadcast done message after all complaints DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + // wait until all parties in QUAL done or aborted for (int i:QUAL) { - while (parties[i - 1].doneFlag && !parties[i - 1].aborted) { + while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { try { - Thread.sleep(300); + Thread.sleep(SleepTime); } catch (InterruptedException e) { // do nothing } } } - int counter = 0; + // broadcast i private secret foreach i in QUAL that aborted for (int i:QUAL) { if(parties[i - 1].aborted){ - counter++; sdkg.broadcastAnswer(user, parties[i - 1].share, parties[i - 1].shareT, i); } } + // wait until at least t + 1 secrets will received foreach i in QUAL that aborted for (int i:QUAL) { if(parties[i - 1].aborted){ - while (parties[i - 1].restoreSharesSet.size() < n - counter) { + while (parties[i - 1].restoreSharesSet.size() <= t) { try { - Thread.sleep(300); + Thread.sleep(SleepTime); } catch (InterruptedException e) { // do nothing } @@ -115,37 +118,50 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera } } + // restore necessary information for (int i = 0; i < n ; i++) { if(parties[i].restoreSharesSet.isEmpty()){ continue; } - try { - Polynomial.Point[] shares = new Polynomial.Point[parties[i].restoreSharesSet.size()]; - parties[i].restoreSharesSet.toArray(shares); - Polynomial polynomial = SecretSharing.restorePolynomial(shares,arithmetic); - BigInteger[] coefficients = polynomial.getCoefficients(); - for (int k = 0 ; k <= t; k++){ - parties[i].commitments[k] = group.multiply(g,coefficients[k]); + Polynomial.Point[] shares = new Polynomial.Point[t + 1]; + int j = 0; + for (Polynomial.Point share: parties[i].restoreSharesSet){ + shares[j++] = share; + if (j >= shares.length){ + break; } - parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); - - } catch (Exception e) { - // } + Polynomial polynomial = SecretSharing.restorePolynomial(shares,arithmetic); + BigInteger[] coefficients = polynomial.getCoefficients(); + for (int k = 0 ; k <= t; k++){ + parties[i].commitments[k] = group.multiply(g,coefficients[k]); + } + parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); } } + /** + * notifies mail handler that stage 4 was started + */ + protected void setStage4(){ + this.isStage4 = true; + SecureDistributedKeyGenerationMailHandler handler = + (SecureDistributedKeyGenerationMailHandler)user.getMailHandler(); + handler.setStage4(true); + } + @Override protected void stage4() { - isStage4 = true; - ((SecureDistributedKeyGenerationMailHandler)user.getMailHandler()).setStage4(true); + setStage4(); ys(); super.stage4(); } - boolean isStage4 = false; - boolean isVerificationValue = true; + private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ + /** + * as in super, with extension to double secret message + */ protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() .setI(doubleSecretMessage.getI()) @@ -155,16 +171,26 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera return super.isValidSecretMessage(sender,isBroadcast,secretMessage); } + /** + * as in super, with extension to double secret message + */ @Override public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); - parties[i - 1].share = extractSecret(id, doubleSecretMessage.getSecret()); parties[i - 1].shareT = extractSecret(id, doubleSecretMessage.getSecretT()); } } + + /** + * 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, DKGMessages.DoubleSecretMessage doubleSecretMessage) { if(!isStage4) { DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() @@ -176,10 +202,15 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera }else{ int i = doubleSecretMessage.getI(); int j = doubleSecretMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); + return isBroadcast && j == sender && parties[i -1].aborted && !parties[j - 1].aborted + && QUAL.contains(i) && QUAL.contains(j); } } + /** + * if !isStage4 as super, with extension to double secret message + * else saves secret + */ @Override public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; @@ -190,9 +221,14 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera Polynomial.Point secretT = extractSecret(j, doubleSecretMessage.getSecretT()); if (!isStage4) { if (sdkg.isValidSecret(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplainState.NonDisqualified; + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.NonDisqualified; + } else { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplainState.Disqualified; + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.Disqualified; + } + if(j == id){ + parties[i - 1].share = secret; + parties[i - 1].shareT = secretT; } } else { parties[i - 1].restoreSharesSet.add(secret); @@ -200,35 +236,52 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera } } + /** + * 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].doneFlag; + return isBroadcast && !parties[sender - 1].ysDoneFlag; } } + /** + * as in super with respect to protocol state + */ @Override public void handelDoneMessage(int sender, boolean isBroadcast, Message message) { if(!isStage4) super.handelDoneMessage(sender, isBroadcast, message); else{ if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].doneFlag = false; + parties[sender - 1].ysDoneFlag = true; } } } + /** + * 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, - DKGMessages.DoubleSecretMessage ysComplaintMessage){ - int i = ysComplaintMessage.getI(); - int j = ysComplaintMessage.getJ(); + DKGMessages.DoubleSecretMessage complaintMessage){ + int i = complaintMessage.getI(); + int j = complaintMessage.getJ(); return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); } - - + /** + * 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 + */ @Override public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { if(!isStage4) { @@ -240,10 +293,9 @@ public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenera int j = ysComplaintMessage.getJ(); Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); - if (sdkg.isValidSecret(secret, secretT, parties[i - 1].commitments, j) - && !sdkg.isValidSecret(secret,parties[i - 1].commitments, j)) { - parties[i - 1].restoreSharesSet.add(secret); - sdkg.broadcastAnswer(user, secret, secretT, i); + if (sdkg.isValidSecret(secret, secretT, parties[i - 1].verifiableValues, j) + && !dkg.isValidSecret(secret,parties[i - 1].commitments, j)) { + parties[i - 1].aborted = true; } } } diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java index d3815ff..6fd93ce 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java @@ -1,5 +1,7 @@ package ShamirSecretSharing; +import Arithmetics.Arithmetic; + import java.math.BigInteger; /** @@ -34,29 +36,29 @@ class LagrangePolynomial{ * 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 - * - * @throws Exception there exists i != j s.t points[i].x == points[j].x + * @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) throws Exception { + public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points,Arithmetic 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[]{BigInteger.ZERO.subtract(points[i].x),BigInteger.ONE}); // X - Xi + 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 = Polynomial.ONE; + product = one; divisor = BigInteger.ONE; for (int j = 0; j < points.length; j++) { if (i != j) { - divisor = divisor.multiply(points[i].x.subtract(points[j].x)); + divisor = arithmetic.mul(divisor,arithmetic.sub(points[i].x,points[j].x)); product = product.mul(factors[j]); } } if(divisor.equals(BigInteger.ZERO)) - throw new Exception(); + return null; lagrangePolynomials[i] = new LagrangePolynomial(product,points[i].y,divisor); } return lagrangePolynomials; diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index 119cf61..ac7fc79 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -1,7 +1,6 @@ package ShamirSecretSharing; import Arithmetics.Arithmetic; -import Arithmetics.Z; import java.math.BigInteger; import java.util.Arrays; @@ -10,7 +9,6 @@ import java.util.Arrays; * Created by Tzlil on 1/27/2016. */ public class Polynomial implements Comparable { - public static final Polynomial ONE = new Polynomial(new BigInteger[]{BigInteger.ONE}); private final int degree; private final BigInteger[] coefficients; private final Arithmetic arithmetic; @@ -18,12 +16,9 @@ public class Polynomial implements Comparable { /** * constructor * @param coefficients + * @param arithmetic * degree set as max index such that coefficients[degree] not equals zero */ - public Polynomial(BigInteger[] coefficients) { - this(coefficients,new Z()); - } - public Polynomial(BigInteger[] coefficients,Arithmetic arithmetic) { int d = coefficients.length - 1; while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){ @@ -34,7 +29,9 @@ public class Polynomial implements Comparable { this.arithmetic = arithmetic; } - + /* + * use for tests + */ @Override public int compareTo(Polynomial other) { if (this.degree != other.degree) @@ -49,15 +46,6 @@ public class Polynomial implements Comparable { return 0; } - @Override - public String toString() { - return "ShamirSecretSharing.PolynomialTests{" + - "degree=" + degree + - ", coefficients=" + java.util.Arrays.toString(coefficients) + - '}'; - } - - /** * @param x * @return sum of coefficients[i] * (x ^ i) @@ -76,8 +64,11 @@ public class Polynomial implements Comparable { * @param points * @return polynomial of minimal degree which goes through all points */ - public static Polynomial interpolation(Point[] points, Arithmetic arithmetic) throws Exception { - LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points); + public static Polynomial interpolation(Point[] points, Arithmetic 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++){ diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 877d272..0f424f9 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -4,6 +4,7 @@ import Arithmetics.Arithmetic; import Arithmetics.Fp; import java.math.BigInteger; +import java.util.Collection; import java.util.Random; /** @@ -67,13 +68,12 @@ public class SecretSharing{ public static BigInteger restoreSecret(Polynomial.Point[] shares,Arithmetic arithmetic) throws Exception { return restorePolynomial(shares,arithmetic).image(BigInteger.ZERO); } - /** * @param shares - subset of the original shares * * @return interpolation(shares) */ - public static Polynomial restorePolynomial(Polynomial.Point[] shares,Arithmetic arithmetic) throws Exception { + public static Polynomial restorePolynomial(Polynomial.Point[] shares,Arithmetic arithmetic) { return Polynomial.interpolation(shares,arithmetic); } diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java deleted file mode 100644 index a50c75c..0000000 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGDeepTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package JointFeldmanProtocol; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import UserInterface.DistributedKeyGenerationUser; -import org.factcenter.qilin.primitives.Group; -import org.factcenter.qilin.primitives.concrete.Zpstar; -import org.junit.Before; -import org.junit.Test; - -import java.lang.reflect.Array; -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 DKGDeepTest { - - int tests = 10; - BigInteger p = BigInteger.valueOf(2903); - BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - Group group = new Zpstar(p); - Arithmetic arithmetic = new Fp(q); - int t = 9; - int n = 20; - - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[n]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; - 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.QUAL){ - if(!testable.aborted.contains(i)) - assert (testable.dkgs[i - 1].getPublicValue().equals(publicValue)); - } - - // assert valid verification values - BigInteger expected,verification; - for (int i: testable.QUAL){ - if(!testable.aborted.contains(i)) { - expected = group.multiply(testable.g, testable.dkgs[i - 1].getShare().y); - verification = VerifiableSecretSharing.verify(i, testable.dkgs[i - 1].getCommitments(), group); - assert (expected.equals(verification)); - } - } - - - // restore the secret from shares - ArrayList sharesList = new ArrayList(); - - for(int i : testable.QUAL){ - if(!testable.aborted.contains(i)) - 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.restoreSecret(shares,arithmetic); - assert (calculatedSecret.equals(testable.secret)); - } - - @Test - public void test() throws Exception { - for (int i = 0; i < tests; i++){ - oneTest(i); - } - } - - class Testable{ - Set QUAL; - Set aborted; - Set malicious; - DistributedKeyGenerationUser[] dkgs; - Thread[] threads; - BigInteger g; - BigInteger secret; - public Testable(Random random) { - - this.dkgs = new DistributedKeyGenerationUserImpl[n]; - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); - this.threads = new Thread[n]; - this.g = sampleGenerator(random); - ArrayList ids = new ArrayList(); - for (int id = 1; id<= n ; id++){ - ids.add(id); - } - Network network = new Network(n); - int id; - BigInteger s; - DistributedKeyGeneration dkg; - this.secret = BigInteger.ZERO; - while (!ids.isEmpty()) { - id = ids.remove(random.nextInt(ids.size())); - s = randomIntModQ(random); - dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); - dkgs[id - 1] = randomDKGUser(id,network,dkg,random); - threads[id - 1] = new Thread(dkgs[id - 1]); - if(QUAL.contains(id)){ - this.secret = this.secret.add(s).mod(q); - } - } - - } - - public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ - if (QUAL.size() <= t) { - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - 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,network,abortStage); - case 2:// malicious - malicious.add(id); - return new DKGMaliciousUserImpl(dkg,network,random); - 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); - } - - - } -} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java index e3261f8..ad4aa4d 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java @@ -13,28 +13,33 @@ public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { private final DistributedKeyGeneration maliciousDkg; private final Set falls; - public DKGMaliciousUserImpl(DistributedKeyGeneration dkg, Network network, Random random) { + public DKGMaliciousUserImpl(DistributedKeyGeneration dkg,DistributedKeyGeneration maliciousDKG, Network network,Set falls) { super(dkg, network); - this.falls = selectFalls(random); - this.maliciousDkg = new DistributedKeyGeneration(t,n,randomInt(random),random,dkg.getQ(),g,group,id); - maliciousDkg.setParties(parties); + this.falls = falls; + this.maliciousDkg = maliciousDKG; + maliciousDKG.setParties(parties); } - public Set selectFalls(Random random){ - ArrayList ids = new ArrayList(); - for (int i = 1; i<= n ; i++){ - if(i!=id) { - ids.add(i); - } - } + public static Set selectFallsRandomly(Set ids, Random random){ Set falls = new HashSet(); - int fallsSize = random.nextInt(ids.size()) + 1;// 1 - (n-1) + ArrayList idsList = new ArrayList(); + for (int id : ids){ + idsList.add(id); + } + int fallsSize = random.nextInt(idsList.size()) + 1;// 1 - (n-1) while (falls.size() < fallsSize){ - falls.add(ids.remove(random.nextInt(ids.size()))); + falls.add(idsList.remove(random.nextInt(idsList.size()))); } return falls; } + public static DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Random random){ + BigInteger q = dkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + return new DistributedKeyGeneration(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() + ,dkg.getGenerator(),dkg.getGroup(),dkg.getId()); + } + @Override public void stage1() { dkg.broadcastCommitments(user); @@ -51,11 +56,6 @@ public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { // do nothing } - private BigInteger randomInt(Random random){ - BigInteger q = dkg.getQ(); - return new BigInteger(q.bitLength(), random).mod(q); - } - private void sendSecrets(){ for (int j = 1; j <= n ; j++){ if(j != id){ diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index b50c46e..624aeeb 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -2,121 +2,174 @@ package JointFeldmanProtocol; import Arithmetics.Arithmetic; import Arithmetics.Fp; -import Arithmetics.Z; import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; import UserInterface.DistributedKeyGenerationUser; +import Utils.GenerateRandomPrime; 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.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; /** - * Created by Tzlil on 2/9/2016. + * Created by Tzlil on 3/21/2016. */ public class DKGTest { - - DistributedKeyGenerationUser[][] dkgsArrays; - Thread[][] threadsArrays; int tests = 10; - BigInteger p = BigInteger.valueOf(2903); + BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - BigInteger[] secrets; - Set QUAL = new HashSet(); - Arithmetic arithmetic; + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + + Testable[] testables; + @Before public void settings(){ - Zpstar zpstar = new Zpstar(p); - Random random = new Random(); - arithmetic = new Fp(q); - BigInteger g; - int t = 9; - int n = 20; - BigInteger ZERO = zpstar.zero(); - dkgsArrays = new DistributedKeyGenerationUserImpl[tests][n]; - threadsArrays = new Thread[tests][n]; - secrets = new BigInteger[tests]; - DistributedKeyGeneration dkg; - int abortedStage = 1; - for (int test = 0; test < tests; test++) { - do { - g = zpstar.sample(random); - } while (!g.equals(ZERO) && !zpstar.multiply(g, q).equals(ZERO));// sample from QRZp* - secrets[test] = BigInteger.ZERO; - Network network = new Network(n); - for (int i = 1; i <= n; i++) { - BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); - dkg = new DistributedKeyGeneration(t,n,secret,random,q,g,zpstar,i); - - if(i == n) { - dkgsArrays[test][i - 1] = new DKGMaliciousUserImpl(dkg,network,random);//new DKGUserImplAbort(dkg, network, abortedStage); - } - else { - dkgsArrays[test][i - 1] = new DistributedKeyGenerationUserImpl(dkg, network); - QUAL.add(i); - } - if (abortedStage > 1 || (abortedStage == 1 && i != n)){ - secrets[test] = secrets[test].add(secret).mod(q); - } - threadsArrays[test][i - 1] = new Thread(dkgsArrays[test][i - 1]); - } + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); } } - public void oneTest(Thread[] threads, DistributedKeyGenerationUser[] dkgs,BigInteger secret) throws Exception { - for (int i = 0; i < threads.length ; i++){ - threads[i].start(); + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + for (int i = 0; i < testable.threads.length ; i++){ + testable.threads[i].start(); } - for (int i = 0; i < threads.length ; i++){ - threads[i].join(); + for (int i = 0; i < testable.threads.length ; i++){ + testable.threads[i].join(); } - int t = dkgs[0].getT(); - int n = dkgs[0].getN(); - - Group zpstar = dkgs[0].getGroup(); - BigInteger g = dkgs[0].getGenerator(); // got the right public value - BigInteger publicValue = zpstar.multiply(g,secret); - for (int i: QUAL){ - if(i != n) - assert (dkgs[i - 1].getPublicValue().equals(publicValue)); + 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: QUAL){ - expected = zpstar.multiply(g, dkgs[i - 1].getShare().y); - verification = VerifiableSecretSharing.verify(i, dkgs[i - 1].getCommitments(),zpstar); + for (int i: testable.valids){ + expected = group.multiply(testable.g, testable.dkgs[i - 1].getShare().y); + verification = VerifiableSecretSharing.verify(i, testable.dkgs[i - 1].getCommitments(), group); assert (expected.equals(verification)); } // restore the secret from shares ArrayList sharesList = new ArrayList(); - Polynomial.Point[] shares = new Polynomial.Point[QUAL.size()]; - for(int i : QUAL){ - sharesList.add(dkgs[i - 1].getShare()); + + 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.restoreSecret(shares,arithmetic); - assert (calculatedSecret.equals(secret)); - + assert (calculatedSecret.equals(testable.secret)); } @Test - public void DKGTest() throws Exception { - for (int i = 0 ; i < dkgsArrays.length; i ++){ - oneTest(threadsArrays[i],dkgsArrays[i],secrets[i]); + public void test() throws Exception { + for (int i = 0; i < tests; i++){ + oneTest(i); } } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] dkgs; + Thread[] threads; + BigInteger g; + BigInteger secret; + + public Testable(Random random) { + this.dkgs = new DistributedKeyGenerationUserImpl[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + Network network = new Network(n); + int id; + BigInteger s; + DistributedKeyGeneration dkg; + this.secret = BigInteger.ZERO; + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); + dkgs[id - 1] = randomDKGUser(id,network,dkg,random); + threads[id - 1] = new Thread(dkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + 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,network,abortStage); + case 2:// malicious + malicious.add(id); + Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); + DistributedKeyGeneration maliciousDKG = DKGMaliciousUserImpl.generateMaliciousDKG(dkg,random); + return new DKGMaliciousUserImpl(dkg,maliciousDKG,network,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); + } + + } } diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java new file mode 100644 index 0000000..9240dea --- /dev/null +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java @@ -0,0 +1,64 @@ +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGeneration; + +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/29/2016. + */ +public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUserImpl { + + private final DistributedKeyGeneration maliciousSDKG; + private final Set falls; + public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg,SecureDistributedKeyGeneration maliciousSDKG + , Network network,Set falls) { + super(sdkg, network); + this.falls = falls; + this.maliciousSDKG = maliciousSDKG; + maliciousSDKG.setParties(parties); + } + + public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Random random){ + BigInteger q = sdkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + return new SecureDistributedKeyGeneration(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() + ,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId()); + } + + @Override + public void stage1() { + sdkg.broadcastVerificationValues(user); + //sdkg.sendSecrets(user); + sendSecrets(); //insteadof dkg.sendSecrets(user); + } + + @Override + public void stage3() { + stopReceiver(); + maliciousSDKG.answerAllComplainingPlayers(user); + } + + @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(user,j); + }else { + sdkg.sendSecret(user, j); + } + } + } + } + +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java index 107f87c..1b1b261 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java @@ -2,12 +2,16 @@ package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; import Arithmetics.Arithmetic; import Arithmetics.Fp; -import Arithmetics.Z; import Communication.Network; import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import JointFeldmanProtocol.DKGMaliciousUserImpl; +import JointFeldmanProtocol.DKGUserImplAbort; +import JointFeldmanProtocol.DistributedKeyGeneration; +import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; import ShamirSecretSharing.Polynomial; import ShamirSecretSharing.SecretSharing; import UserInterface.DistributedKeyGenerationUser; +import Utils.GenerateRandomPrime; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; @@ -20,108 +24,157 @@ import java.util.Random; import java.util.Set; /** - * Created by Tzlil on 2/23/2016. + * Created by Tzlil on 3/29/2016. */ public class SDKGTest { - DistributedKeyGenerationUser[][] sdkgsArrays; - Thread[][] threadsArrays; int tests = 10; - BigInteger p = BigInteger.valueOf(2903); + BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - BigInteger[] secrets; - - Set QUAL = new HashSet(); - - Arithmetic arithmetic; + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + Testable[] testables; @Before public void settings(){ - Zpstar zpstar = new Zpstar(p); - Random random = new Random(); - arithmetic = new Fp(q); - BigInteger g,h; - int t = 9; - int n = 20; - BigInteger ZERO = zpstar.zero(); - sdkgsArrays = new SecureDistributedKeyGenerationUserImpl[tests][n]; - threadsArrays = new Thread[tests][n]; - secrets = new BigInteger[tests]; - SecureDistributedKeyGeneration sdkg; - for (int test = 0; test < tests; test++) { - do { - g = zpstar.sample(random); - } while (!g.equals(ZERO) && !zpstar.multiply(g, q).equals(ZERO));// sample from QRZp* - h = zpstar.multiply(g,BigInteger.valueOf(2)); - secrets[test] = BigInteger.ZERO; - Network network = new Network(n); - int abortedStage = 2; - for (int i = 1; i <= n; i++) { - BigInteger secret = new BigInteger(q.bitLength(), random).mod(q); - sdkg = new SecureDistributedKeyGeneration(t,n,secret,random,q,g,h,zpstar,i); - if(i == n) { - sdkgsArrays[test][i - 1] = new SDKGUserImplAbort(sdkg, network, abortedStage); - } - else { - sdkgsArrays[test][i - 1] = new SecureDistributedKeyGenerationUserImpl(sdkg, network); - QUAL.add(i); - } - if (abortedStage > 1 || (abortedStage == 1 && i != n)){ - secrets[test] = secrets[test].add(secret).mod(q); - } - threadsArrays[test][i - 1] = new Thread(sdkgsArrays[test][i - 1]); - } + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); } } - - public void oneTest(Thread[] threads, DistributedKeyGenerationUser[] dkgs,BigInteger secret) throws Exception { - for (int i = 0; i < threads.length ; i++){ - threads[i].start(); + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + for (int i = 0; i < testable.threads.length ; i++){ + testable.threads[i].start(); } - for (int i = 0; i < threads.length ; i++){ - threads[i].join(); + for (int i = 0; i < testable.threads.length ; i++){ + testable.threads[i].join(); } - int t = dkgs[0].getT(); - int n = dkgs[0].getN(); - - Group zpstar = dkgs[0].getGroup(); - BigInteger g = dkgs[0].getGenerator(); // got the right public value - BigInteger publicValue = zpstar.multiply(g,secret); - for (int i: QUAL){ - assert (dkgs[i - 1].getPublicValue().equals(publicValue)); + 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: QUAL){ - expected = zpstar.multiply(g, dkgs[i - 1].getShare().y); - verification = VerifiableSecretSharing.verify(i, dkgs[i - 1].getCommitments(),zpstar); + for (int i: testable.valids){ + expected = group.multiply(testable.g, testable.sdkgs[i - 1].getShare().y); + verification = VerifiableSecretSharing.verify(i, testable.sdkgs[i - 1].getCommitments(), group); assert (expected.equals(verification)); } // restore the secret from shares ArrayList sharesList = new ArrayList(); - Polynomial.Point[] shares = new Polynomial.Point[QUAL.size()]; - for(int i : QUAL){ - sharesList.add(dkgs[i - 1].getShare()); + + 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.restoreSecret(shares,arithmetic); - assert (calculatedSecret.equals(secret)); - + assert (calculatedSecret.equals(testable.secret)); } @Test - public void SDKGTest() throws Exception { - for (int i = 0 ; i < sdkgsArrays.length; i ++){ - oneTest(threadsArrays[i],sdkgsArrays[i],secrets[i]); + public void test() throws Exception { + for (int i = 0; i < tests; i++){ + oneTest(i); } } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] sdkgs; + Thread[] threads; + BigInteger g; + BigInteger h; + BigInteger secret; + + public Testable(Random random) { + this.sdkgs = new SecureDistributedKeyGenerationUserImpl[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + this.h = group.multiply(g,randomIntModQ(random)); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + Network network = new Network(n); + int id; + BigInteger s; + SecureDistributedKeyGeneration sdkg; + this.secret = BigInteger.ZERO; + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id); + sdkgs[id - 1] = randomSDKGUser(id,network,sdkg,random); + threads[id - 1] = new Thread(sdkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public SecureDistributedKeyGenerationUserImpl randomSDKGUser(int id,Network network, SecureDistributedKeyGeneration sdkg,Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUserImpl(sdkg,network); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUserImpl(sdkg,network); + case 1:// abort + int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 + aborted.add(id); + if (abortStage > 1){ + QUAL.add(id); + } + return new SDKGUserImplAbort(sdkg,network,abortStage); + case 2:// malicious + malicious.add(id); + Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); + SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,random); + return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,network,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); + } + + } } diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java index fc777d3..c2a6fbe 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java @@ -18,7 +18,8 @@ public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { this.stage = 1; } - private void sendAbort(){ + private void abort(){ + stopReceiver(); user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); } @@ -27,7 +28,7 @@ public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { if(stage < abortStage) super.stage1(); else if(stage == abortStage){ - sendAbort(); + abort(); } stage++; } @@ -37,7 +38,7 @@ public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { if(stage < abortStage) super.stage2(); else if(stage == abortStage){ - sendAbort(); + abort(); } stage++; } @@ -47,7 +48,7 @@ public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { if(stage < abortStage) super.stage3(); else if(stage == abortStage){ - sendAbort(); + abort(); } stage++; } @@ -57,7 +58,7 @@ public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { if(stage < abortStage) super.stage4(); else if(stage == abortStage){ - sendAbort(); + abort(); } stage++; } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java index 288aed1..fe4e602 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java @@ -1,4 +1,6 @@ package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; @@ -24,8 +26,8 @@ public class AddTest { arr1 = new Polynomial[tests]; arr2 = new Polynomial[tests]; for (int i = 0; i < arr1.length; i++){ - arr1[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); - arr2[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z()); + arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z()); } } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index 2f5ba39..97f1b8d 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -2,8 +2,9 @@ package ShamirSecretSharing.PolynomialTests; import Arithmetics.Arithmetic; import Arithmetics.Fp; -import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; import ShamirSecretSharing.Polynomial; +import Utils.GenerateRandomPrime; import org.junit.Before; import org.junit.Test; @@ -23,7 +24,7 @@ public class InterpolationTest { Random random; Polynomial.Point[][] pointsArrays; Arithmetic arithmetic; - BigInteger p = BigInteger.valueOf(2903); + BigInteger p = GenerateRandomPrime.SafePrime100Bits; @Before public void settings(){ @@ -31,7 +32,7 @@ public class InterpolationTest { polynomials = new Polynomial[tests]; pointsArrays = new Polynomial.Point[tests][]; for (int i = 0; i < polynomials.length; i++){ - polynomials[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); + polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); pointsArrays[i] = randomPoints(polynomials[i]); } arithmetic = new Fp(p); diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java index 0865058..3a3bf1a 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java @@ -1,5 +1,7 @@ package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; @@ -26,7 +28,7 @@ public class MulByConstTest { arr1 = new Polynomial[tests]; arr2 = new BigInteger[tests]; for (int i = 0; i < arr1.length; i++){ - arr1[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z()); arr2[i] = new BigInteger(bits,random); } } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java index 418ea00..a7dd365 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java @@ -1,5 +1,7 @@ package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; import ShamirSecretSharing.Polynomial; import org.junit.Before; import org.junit.Test; @@ -26,8 +28,8 @@ public class MulTest { arr1 = new Polynomial[tests]; arr2 = new Polynomial[tests]; for (int i = 0; i < arr1.length; i++){ - arr1[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); - arr2[i] = Utils.generateRandomPolynomial(random.nextInt(maxDegree),bits,random); + arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z()); + arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z()); } } diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java index 042c06a..a74148f 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java @@ -1,6 +1,7 @@ package ShamirSecretSharing; import Arithmetics.Z; +import Utils.GenerateRandomPrime; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; import org.junit.Before; @@ -24,7 +25,7 @@ public class SecretSharingTest { @Before public void settings(){ - BigInteger p = BigInteger.valueOf(2903); + BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); group = new Zn(p); int t = 9; diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java similarity index 75% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java rename to destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java index 8ec057a..d59d051 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/Utils.java +++ b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java @@ -1,5 +1,6 @@ -package ShamirSecretSharing.PolynomialTests; +package Utils; +import Arithmetics.Arithmetic; import Arithmetics.Fp; import ShamirSecretSharing.Polynomial; @@ -9,19 +10,19 @@ import java.util.Random; /** * Created by Tzlil on 1/27/2016. */ -public class Utils { +public class GenerateRandomPolynomial { - public static Polynomial generateRandomPolynomial(int degree,int bits,Random random) { + public static Polynomial generateRandomPolynomial(int degree, int bits, Random random,Arithmetic 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); + return new Polynomial(coefficients,arithmetic); } public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) { - BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random).getCoefficients(); + BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random,new Fp(p)).getCoefficients(); for (int i = 0; i Date: Tue, 5 Apr 2016 15:36:00 +0300 Subject: [PATCH 035/106] Code review comments and channges --- .gitignore | 32 +- build.gradle | 20 +- build.gradle-template | 440 ++++---- .../bulletinboard/BulletinClientJob.java | 162 +-- .../BulletinClientJobResult.java | 58 +- .../bulletinboard/BulletinClientWorker.java | 434 ++++---- .../SimpleBulletinBoardClient.java | 322 +++--- .../ThreadedBulletinBoardClient.java | 262 ++--- .../callbacks/ClientFutureCallback.java | 50 +- .../GetRedundancyFutureCallback.java | 76 +- .../callbacks/PostMessageFutureCallback.java | 92 +- .../callbacks/ReadMessagesFutureCallback.java | 76 +- .../BulletinBoardClientIntegrationTest.java | 428 ++++---- bulletin-board-server/.gitignore | 2 +- bulletin-board-server/build.gradle | 482 ++++----- bulletin-board-server/gradle-app.setting | 58 +- .../bulletinboard/service/HelloProtoBuf.java | 60 +- .../sqlserver/BulletinBoardSQLServer.java | 968 +++++++++--------- .../sqlserver/H2QueryProvider.java | 328 +++--- .../sqlserver/MySQLQueryProvider.java | 296 +++--- .../sqlserver/SQLiteQueryProvider.java | 246 ++--- .../sqlserver/mappers/EntryNumMapper.java | 36 +- .../sqlserver/mappers/MessageMapper.java | 64 +- .../sqlserver/mappers/SignatureMapper.java | 56 +- .../webapp/BulletinBoardWebApp.java | 248 ++--- .../webapp/HelloProtoWebApp.java | 100 +- .../proto/meerkat/bulletin_board_server.proto | 16 +- .../src/main/webapp/META-INF/jetty-env.xml | 22 +- .../src/main/webapp/WEB-INF/web.xml | 76 +- ...BulletinBoardSQLServerIntegrationTest.java | 248 ++--- .../GenericBulletinBoardServerTest.java | 782 +++++++------- .../H2BulletinBoardServerTest.java | 244 ++--- .../HelloProtoIntegrationTest.java | 84 +- .../MySQLBulletinBoardServerTest.java | 252 ++--- .../SQLiteBulletinBoardServerTest.java | 212 ++-- destributed-key-generation/build.gradle | 440 ++++---- .../src/main/java/Arithmetics/Arithmetic.java | 32 +- .../src/main/java/Arithmetics/Fp.java | 76 +- .../src/main/java/Arithmetics/Z.java | 58 +- .../src/main/java/Communication/Channel.java | 28 + .../main/java/Communication/MailHandler.java | 117 ++- .../java/Communication/MessageHandler.java | 30 +- .../src/main/java/Communication/Network.java | 148 +-- .../src/main/java/Communication/User.java | 140 +-- .../VerifiableSecretSharing.java | 198 ++-- .../DistributedKeyGeneration.java | 513 +++++----- .../DistributedKeyGenerationMailHandler.java | 98 +- .../DistributedKeyGenerationParty.java | 63 +- .../DistributedKeyGenerationUserImpl.java | 775 +++++++------- .../SecureDistributedKeyGeneration.java | 278 ++--- ...reDistributedKeyGenerationMailHandler.java | 126 +-- .../SecureDistributedKeyGenerationParty.java | 58 +- ...ecureDistributedKeyGenerationUserImpl.java | 611 +++++------ .../LagrangePolynomial.java | 132 +-- .../java/ShamirSecretSharing/Polynomial.java | 415 ++++---- .../ShamirSecretSharing/SecretSharing.java | 223 ++-- .../DistributedKeyGenerationUser.java | 26 +- .../java/UserInterface/SecretSharingUser.java | 28 +- .../VerifiableSecretSharingUser.java | 32 +- .../VerifiableSecretSharingTest.java | 135 ++- .../DKGMaliciousUserImpl.java | 144 +-- .../java/JointFeldmanProtocol/DKGTest.java | 350 +++---- .../DKGUserImplAbort.java | 126 +-- .../SDKGMaliciousUserImpl.java | 125 ++- .../SDKGTest.java | 357 ++++--- .../SDKGUserImplAbort.java | 130 +-- .../PolynomialTests/AddTest.java | 92 +- .../PolynomialTests/InterpolationTest.java | 136 +-- .../PolynomialTests/MulByConstTest.java | 96 +- .../PolynomialTests/MulTest.java | 96 +- .../SecretSharingTest.java | 126 +-- .../java/Utils/GenerateRandomPolynomial.java | 62 +- .../test/java/Utils/GenerateRandomPrime.java | 64 +- gradle/wrapper/gradle-wrapper.properties | 12 +- meerkat-common/.gitignore | 2 +- meerkat-common/build.gradle | 436 ++++---- meerkat-common/src/main/java/Demo.java | 58 +- .../bulletinboard/BulletinBoardClient.java | 108 +- .../bulletinboard/BulletinBoardServer.java | 84 +- .../meerkat/comm/CommunicationException.java | 72 +- .../src/main/java/meerkat/comm/Timestamp.java | 14 +- .../src/main/java/meerkat/crypto/Digest.java | 76 +- .../java/meerkat/crypto/DigitalSignature.java | 192 ++-- .../main/java/meerkat/crypto/Encryption.java | 80 +- .../concrete/ECDSADeterministicSignature.java | 268 ++--- .../crypto/concrete/ECDSASignature.java | 644 ++++++------ .../crypto/concrete/ECElGamalEncryption.java | 270 ++--- .../crypto/concrete/GlobalCryptoSetup.java | 86 +- .../meerkat/crypto/concrete/SHA256Digest.java | 192 ++-- .../mixnet/Mix2ZeroKnowledgeProver.java | 36 +- .../mixnet/Mix2ZeroKnowledgeVerifier.java | 46 +- .../java/meerkat/crypto/mixnet/Mixer.java | 22 +- .../java/meerkat/crypto/mixnet/Trustee.java | 14 +- .../java/meerkat/crypto/mixnet/Verifier.java | 14 +- .../java/meerkat/logging/LogVerifier.java | 14 +- .../src/main/java/meerkat/logging/Logger.java | 14 +- .../util/BulletinBoardMessageComparator.java | 98 +- .../src/main/java/meerkat/util/Hex.java | 52 +- .../main/java/meerkat/voting/VotingBooth.java | 140 +-- .../main/proto/meerkat/BulletinBoardAPI.proto | 158 +-- .../src/main/proto/meerkat/DKGMessages.proto | 96 +- .../main/proto/meerkat/concrete_crypto.proto | 42 +- .../src/main/proto/meerkat/crypto.proto | 108 +- .../src/main/proto/meerkat/mixing.proto | 22 +- .../src/main/proto/meerkat/voting.proto | 180 ++-- .../src/main/resources/logback.groovy | 92 +- .../ECDSADeterministicSignatureTest.java | 100 +- .../crypto/concrete/ECDSASignatureTest.java | 440 ++++---- .../concrete/ECElGamalEncryptionTest.java | 244 ++--- .../crypto/concrete/ECElGamalUtils.java | 178 ++-- .../src/test/resources/certs/README.md | 12 +- .../user1-key-with-password-secret.pem | 16 +- .../certs/enduser-certs/user1-key.pem | 10 +- .../certs/enduser-certs/user1-pubkey.pem | 8 +- .../resources/certs/enduser-certs/user1.crt | 38 +- .../resources/certs/enduser-certs/user1.csr | 18 +- .../certs/enduser-certs/user2-key.pem | 10 +- .../certs/enduser-certs/user2-pubkey.pem | 8 +- .../resources/certs/enduser-certs/user2.crt | 38 +- .../resources/certs/enduser-certs/user2.csr | 18 +- .../certs/intermediate-ca-1/1000.pem | 38 +- .../certs/intermediate-ca-1/1001.pem | 38 +- .../certs/intermediate-ca-1/certindex | 4 +- .../certs/intermediate-ca-1/certindex.attr | 2 +- .../intermediate-ca-1/certindex.attr.old | 2 +- .../certs/intermediate-ca-1/certindex.old | 2 +- .../certs/intermediate-ca-1/certserial | 2 +- .../certs/intermediate-ca-1/certserial.old | 2 +- .../certs/intermediate-ca-1/crlnumber | 2 +- .../intermediate-ca-1-private-key.pem | 10 +- .../intermediate-ca-1/intermediate-ca-1.crt | 42 +- .../intermediate-ca-1/intermediate-ca-1.csr | 20 +- .../openssl-intermediate-ca.conf | 92 +- .../src/test/resources/certs/root-ca/1000.pem | 42 +- .../test/resources/certs/root-ca/certindex | 2 +- .../resources/certs/root-ca/certindex.attr | 2 +- .../test/resources/certs/root-ca/certserial | 2 +- .../resources/certs/root-ca/certserial.old | 2 +- .../test/resources/certs/root-ca/crlnumber | 2 +- .../resources/certs/root-ca/openssl-ca.conf | 122 +-- ...ot-ca-private-key-with-password-secret.pem | 16 +- .../certs/root-ca/root-ca-private-key.pem | 10 +- .../test/resources/certs/root-ca/root-ca.crt | 34 +- .../src/test/resources/certs/secp256k1.pem | 6 +- polling-station/build.gradle | 388 +++---- restful-api-common/.gitignore | 2 +- restful-api-common/build.gradle | 320 +++--- .../src/main/java/meerkat/rest/Constants.java | 24 +- .../rest/ProtobufMessageBodyReader.java | 82 +- .../rest/ProtobufMessageBodyWriter.java | 82 +- settings.gradle | 16 +- voting-booth/build.gradle | 386 +++---- 152 files changed, 10399 insertions(+), 10293 deletions(-) create mode 100644 destributed-key-generation/src/main/java/Communication/Channel.java diff --git a/.gitignore b/.gitignore index 6339218..6c07527 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,16 @@ -.gradle -.idea -build -bin -.settings -.classpath -.project -out -*.iml -*.ipr -*.iws -**/*.swp -*.prefs -*.project -*.classpath -bulletin-board-server/local-instances/meerkat.db +.gradle +.idea +build +bin +.settings +.classpath +.project +out +*.iml +*.ipr +*.iws +**/*.swp +*.prefs +*.project +*.classpath +bulletin-board-server/local-instances/meerkat.db diff --git a/build.gradle b/build.gradle index 9f070e3..e3f1a0c 100644 --- a/build.gradle +++ b/build.gradle @@ -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() } + } + } +} diff --git a/build.gradle-template b/build.gradle-template index 60ec7c9..074667f 100644 --- a/build.gradle-template +++ b/build.gradle-template @@ -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 + } + } + } +} + + + diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java index aca98d4..175cd91 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJob.java @@ -1,82 +1,82 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 09-Dec-15. - * - * This class specifies the job that is required of a Bulletin Board Client Worker - */ -public class BulletinClientJob { - - public static enum JobType{ - POST_MESSAGE, // Post a message to servers - READ_MESSAGES, // Read messages according to some given filter (any server will do) - GET_REDUNDANCY // Check the redundancy of a specific message in the databases - } - - private List serverAddresses; - - private int minServers; // The minimal number of servers the job must be successful on for the job to be completed - - private final JobType jobType; - - private final Message payload; // The information associated with the job type - - private int maxRetry; // Number of retries for this job; set to -1 for infinite retries - - public BulletinClientJob(List serverAddresses, int minServers, JobType jobType, Message payload, int maxRetry) { - this.serverAddresses = serverAddresses; - this.minServers = minServers; - this.jobType = jobType; - this.payload = payload; - this.maxRetry = maxRetry; - } - - public void updateServerAddresses(List newServerAdresses) { - this.serverAddresses = newServerAdresses; - } - - public List getServerAddresses() { - return serverAddresses; - } - - public int getMinServers() { - return minServers; - } - - public JobType getJobType() { - return jobType; - } - - public Message getPayload() { - return payload; - } - - public int getMaxRetry() { - return maxRetry; - } - - public void shuffleAddresses() { - Collections.shuffle(serverAddresses); - } - - public void decMinServers(){ - minServers--; - } - - public void decMaxRetry(){ - if (maxRetry > 0) { - maxRetry--; - } - } - - public boolean isRetry(){ - return (maxRetry != 0); - } - +package meerkat.bulletinboard; + +import com.google.protobuf.Message; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 09-Dec-15. + * + * This class specifies the job that is required of a Bulletin Board Client Worker + */ +public class BulletinClientJob { + + public static enum JobType{ + POST_MESSAGE, // Post a message to servers + READ_MESSAGES, // Read messages according to some given filter (any server will do) + GET_REDUNDANCY // Check the redundancy of a specific message in the databases + } + + private List serverAddresses; + + private int minServers; // The minimal number of servers the job must be successful on for the job to be completed + + private final JobType jobType; + + private final Message payload; // The information associated with the job type + + private int maxRetry; // Number of retries for this job; set to -1 for infinite retries + + public BulletinClientJob(List serverAddresses, int minServers, JobType jobType, Message payload, int maxRetry) { + this.serverAddresses = serverAddresses; + this.minServers = minServers; + this.jobType = jobType; + this.payload = payload; + this.maxRetry = maxRetry; + } + + public void updateServerAddresses(List newServerAdresses) { + this.serverAddresses = newServerAdresses; + } + + public List getServerAddresses() { + return serverAddresses; + } + + public int getMinServers() { + return minServers; + } + + public JobType getJobType() { + return jobType; + } + + public Message getPayload() { + return payload; + } + + public int getMaxRetry() { + return maxRetry; + } + + public void shuffleAddresses() { + Collections.shuffle(serverAddresses); + } + + public void decMinServers(){ + minServers--; + } + + public void decMaxRetry(){ + if (maxRetry > 0) { + maxRetry--; + } + } + + public boolean isRetry(){ + return (maxRetry != 0); + } + } \ No newline at end of file diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java index be0501b..6a3998f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientJobResult.java @@ -1,29 +1,29 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; - -/** - * Created by Arbel Deutsch Peled on 09-Dec-15. - * - * This class contains the end status and result of a Bulletin Board Client Job. - */ -public final class BulletinClientJobResult { - - private final BulletinClientJob job; // Stores the job the result refers to - - private final Message result; // The result of the job; valid only if success==true - - public BulletinClientJobResult(BulletinClientJob job, Message result) { - this.job = job; - this.result = result; - } - - public BulletinClientJob getJob() { - return job; - } - - public Message getResult() { - return result; - } - -} +package meerkat.bulletinboard; + +import com.google.protobuf.Message; + +/** + * Created by Arbel Deutsch Peled on 09-Dec-15. + * + * This class contains the end status and result of a Bulletin Board Client Job. + */ +public final class BulletinClientJobResult { + + private final BulletinClientJob job; // Stores the job the result refers to + + private final Message result; // The result of the job; valid only if success==true + + public BulletinClientJobResult(BulletinClientJob job, Message result) { + this.job = job; + this.result = result; + } + + public BulletinClientJob getJob() { + return job; + } + + public Message getResult() { + return result; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index 51599d5..1d0d741 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -1,217 +1,217 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; -import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.rest.Constants; -import meerkat.rest.ProtobufMessageBodyReader; -import meerkat.rest.ProtobufMessageBodyWriter; - -import javax.ws.rs.ProcessingException; -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 java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; - -/** - * Created by Arbel Deutsch Peled on 09-Dec-15. - * - * This class implements the actual communication with the Bulletin Board Servers. - * It is meant to be used in a multi-threaded environment. - */ -//TODO: Maybe make this abstract and inherit from it. -public class BulletinClientWorker implements Callable { - - private final BulletinClientJob job; // The requested job to be handled - - public BulletinClientWorker(BulletinClientJob job){ - this.job = job; - } - - // This resource enabled creation of a single Client per thread. - private static final ThreadLocal clientLocal = - new ThreadLocal () { - @Override protected Client initialValue() { - Client client; - client = ClientBuilder.newClient(); - client.register(ProtobufMessageBodyReader.class); - client.register(ProtobufMessageBodyWriter.class); - - return client; - } - }; - - // This resource enables creation of a single Digest per thread. - private static final ThreadLocal digestLocal = - new ThreadLocal () { - @Override protected Digest initialValue() { - Digest digest; - digest = new SHA256Digest(); //TODO: Make this generic. - - return digest; - } - }; - - /** - * This method carries out the actual communication with the servers via HTTP Post - * It accesses the servers according to the job it received and updates said job as it goes - * The method will only iterate once through the server list, removing servers from the list when they are no longer required - * In a POST_MESSAGE job: successful post to a server results in removing the server from the list - * In a GET_REDUNDANCY job: no server is removed from the list and the (absolute) number of servers in which the message was found is returned - * In a READ_MESSAGES job: successful retrieval from any server terminates the method and returns the received values; The list is not changed - * @return The original job, modified to fit the current state and the required output (if any) of the operation - * @throws IllegalArgumentException - * @throws CommunicationException - */ - public BulletinClientJobResult call() throws IllegalArgumentException, CommunicationException{ - - Client client = clientLocal.get(); - Digest digest = digestLocal.get(); - - WebTarget webTarget; - Response response; - - String requestPath; - Message msg; - - List serverAddresses = new LinkedList(job.getServerAddresses()); - - Message payload = job.getPayload(); - - BulletinBoardMessageList msgList; - - int count = 0; // Used to count number of servers which contain the required message in a GET_REDUNDANCY request. - - job.shuffleAddresses(); // This is done to randomize the order of access to servers primarily for READ operations - - // Prepare the request. - switch(job.getJobType()) { - - case POST_MESSAGE: - // Make sure the payload is a BulletinBoardMessage - if (!(payload instanceof BulletinBoardMessage)) { - throw new IllegalArgumentException("Cannot post an object that is not an instance of BulletinBoardMessage"); - } - - msg = payload; - requestPath = Constants.POST_MESSAGE_PATH; - break; - - case READ_MESSAGES: - // Make sure the payload is a MessageFilterList - if (!(payload instanceof MessageFilterList)) { - throw new IllegalArgumentException("Read failed: an instance of MessageFilterList is required as payload for a READ_MESSAGES operation"); - } - - msg = payload; - requestPath = Constants.READ_MESSAGES_PATH; - break; - - case GET_REDUNDANCY: - // Make sure the payload is a MessageId - if (!(payload instanceof MessageID)) { - throw new IllegalArgumentException("Cannot search for an object that is not an instance of MessageID"); - } - - requestPath = Constants.READ_MESSAGES_PATH; - - msg = MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.MSG_ID) - .setId(((MessageID) payload).getID()) - .build() - ).build(); - - break; - - default: - throw new IllegalArgumentException("Unsupported job type"); - - } - - // Iterate through servers - - Iterator addressIterator = serverAddresses.iterator(); - - while (addressIterator.hasNext()) { - - // Send request to Server - String address = addressIterator.next(); - webTarget = client.target(address).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(requestPath); - response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); - - // Retrieve answer - switch(job.getJobType()) { - - case POST_MESSAGE: - try { - - response.readEntity(BoolMsg.class); // If a BoolMsg entity is returned: the post was successful - addressIterator.remove(); // Post to this server succeeded: remove server from list - job.decMinServers(); - - } catch (ProcessingException | IllegalStateException e) {} // Post to this server failed: retry next time - finally { - response.close(); - } - break; - - case GET_REDUNDANCY: - try { - msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful - - if (msgList.getMessageList().size() > 0){ // Message was found in the server. - count++; - } - } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server - finally { - response.close(); - } - break; - - case READ_MESSAGES: - try { - msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful - return new BulletinClientJobResult(job, msgList); // Return the result - } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server - finally { - response.close(); - } - break; - - } - - } - - // Return result (if haven't done so yet) - switch(job.getJobType()) { - - case POST_MESSAGE: - // The job now contains the information required to ascertain whether enough server posts have succeeded - // It will also contain the list of servers in which the post was not successful - job.updateServerAddresses(serverAddresses); - return new BulletinClientJobResult(job, null); - - case GET_REDUNDANCY: - // Return the number of servers in which the message was found - // The job now contains the list of these servers - return new BulletinClientJobResult(job, IntMsg.newBuilder().setValue(count).build()); - - case READ_MESSAGES: - // A successful operation would have already returned an output - // Therefore: no server access was successful - throw new CommunicationException("Could not access any server"); - - default: // This is required for successful compilation - throw new IllegalArgumentException("Unsupported job type"); - - } - } -} +package meerkat.bulletinboard; + +import com.google.protobuf.Message; +import meerkat.comm.CommunicationException; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.rest.Constants; +import meerkat.rest.ProtobufMessageBodyReader; +import meerkat.rest.ProtobufMessageBodyWriter; + +import javax.ws.rs.ProcessingException; +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 java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * Created by Arbel Deutsch Peled on 09-Dec-15. + * + * This class implements the actual communication with the Bulletin Board Servers. + * It is meant to be used in a multi-threaded environment. + */ +//TODO: Maybe make this abstract and inherit from it. +public class BulletinClientWorker implements Callable { + + private final BulletinClientJob job; // The requested job to be handled + + public BulletinClientWorker(BulletinClientJob job){ + this.job = job; + } + + // This resource enabled creation of a single Client per thread. + private static final ThreadLocal clientLocal = + new ThreadLocal () { + @Override protected Client initialValue() { + Client client; + client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + + return client; + } + }; + + // This resource enables creation of a single Digest per thread. + private static final ThreadLocal digestLocal = + new ThreadLocal () { + @Override protected Digest initialValue() { + Digest digest; + digest = new SHA256Digest(); //TODO: Make this generic. + + return digest; + } + }; + + /** + * This method carries out the actual communication with the servers via HTTP Post + * It accesses the servers according to the job it received and updates said job as it goes + * The method will only iterate once through the server list, removing servers from the list when they are no longer required + * In a POST_MESSAGE job: successful post to a server results in removing the server from the list + * In a GET_REDUNDANCY job: no server is removed from the list and the (absolute) number of servers in which the message was found is returned + * In a READ_MESSAGES job: successful retrieval from any server terminates the method and returns the received values; The list is not changed + * @return The original job, modified to fit the current state and the required output (if any) of the operation + * @throws IllegalArgumentException + * @throws CommunicationException + */ + public BulletinClientJobResult call() throws IllegalArgumentException, CommunicationException{ + + Client client = clientLocal.get(); + Digest digest = digestLocal.get(); + + WebTarget webTarget; + Response response; + + String requestPath; + Message msg; + + List serverAddresses = new LinkedList(job.getServerAddresses()); + + Message payload = job.getPayload(); + + BulletinBoardMessageList msgList; + + int count = 0; // Used to count number of servers which contain the required message in a GET_REDUNDANCY request. + + job.shuffleAddresses(); // This is done to randomize the order of access to servers primarily for READ operations + + // Prepare the request. + switch(job.getJobType()) { + + case POST_MESSAGE: + // Make sure the payload is a BulletinBoardMessage + if (!(payload instanceof BulletinBoardMessage)) { + throw new IllegalArgumentException("Cannot post an object that is not an instance of BulletinBoardMessage"); + } + + msg = payload; + requestPath = Constants.POST_MESSAGE_PATH; + break; + + case READ_MESSAGES: + // Make sure the payload is a MessageFilterList + if (!(payload instanceof MessageFilterList)) { + throw new IllegalArgumentException("Read failed: an instance of MessageFilterList is required as payload for a READ_MESSAGES operation"); + } + + msg = payload; + requestPath = Constants.READ_MESSAGES_PATH; + break; + + case GET_REDUNDANCY: + // Make sure the payload is a MessageId + if (!(payload instanceof MessageID)) { + throw new IllegalArgumentException("Cannot search for an object that is not an instance of MessageID"); + } + + requestPath = Constants.READ_MESSAGES_PATH; + + msg = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(((MessageID) payload).getID()) + .build() + ).build(); + + break; + + default: + throw new IllegalArgumentException("Unsupported job type"); + + } + + // Iterate through servers + + Iterator addressIterator = serverAddresses.iterator(); + + while (addressIterator.hasNext()) { + + // Send request to Server + String address = addressIterator.next(); + webTarget = client.target(address).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(requestPath); + response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); + + // Retrieve answer + switch(job.getJobType()) { + + case POST_MESSAGE: + try { + + response.readEntity(BoolMsg.class); // If a BoolMsg entity is returned: the post was successful + addressIterator.remove(); // Post to this server succeeded: remove server from list + job.decMinServers(); + + } catch (ProcessingException | IllegalStateException e) {} // Post to this server failed: retry next time + finally { + response.close(); + } + break; + + case GET_REDUNDANCY: + try { + msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful + + if (msgList.getMessageList().size() > 0){ // Message was found in the server. + count++; + } + } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server + finally { + response.close(); + } + break; + + case READ_MESSAGES: + try { + msgList = response.readEntity(BulletinBoardMessageList.class); // If a BulletinBoardMessageList is returned: the read was successful + return new BulletinClientJobResult(job, msgList); // Return the result + } catch (ProcessingException | IllegalStateException e) {} // Read failed: try with next server + finally { + response.close(); + } + break; + + } + + } + + // Return result (if haven't done so yet) + switch(job.getJobType()) { + + case POST_MESSAGE: + // The job now contains the information required to ascertain whether enough server posts have succeeded + // It will also contain the list of servers in which the post was not successful + job.updateServerAddresses(serverAddresses); + return new BulletinClientJobResult(job, null); + + case GET_REDUNDANCY: + // Return the number of servers in which the message was found + // The job now contains the list of these servers + return new BulletinClientJobResult(job, IntMsg.newBuilder().setValue(count).build()); + + case READ_MESSAGES: + // A successful operation would have already returned an output + // Therefore: no server access was successful + throw new CommunicationException("Could not access any server"); + + default: // This is required for successful compilation + throw new IllegalArgumentException("Unsupported job type"); + + } + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index f340cae..9d3f24a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -1,161 +1,161 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.ByteString; -import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Voting; -import meerkat.protobuf.Voting.BulletinBoardClientParams; -import meerkat.rest.*; - -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; - -/** - * Created by Arbel Deutsch Peled on 05-Dec-15. - */ -public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { - - private List meerkatDBs; - - private Client client; - - private Digest digest; - - /** - * Stores database locations and initializes the web Client - * @param clientParams contains the data needed to access the DBs - */ -// @Override - public void init(Voting.BulletinBoardClientParams clientParams) { - - 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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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 - */ -// @Override - public List 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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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 void registerNewMessageCallback(MessageCallback callback, MessageFilterList filterList) { -// callback.handleNewMessage(readMessages(filterList)); -// } -} +package meerkat.bulletinboard; + +import com.google.protobuf.ByteString; +import meerkat.comm.CommunicationException; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.BulletinBoardClientParams; +import meerkat.rest.*; + +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; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class SimpleBulletinBoardClient{ //implements BulletinBoardClient { + + private List meerkatDBs; + + private Client client; + + private Digest digest; + + /** + * Stores database locations and initializes the web Client + * @param clientParams contains the data needed to access the DBs + */ +// @Override + public void init(Voting.BulletinBoardClientParams clientParams) { + + 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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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 + */ +// @Override + public List 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(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.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 void registerNewMessageCallback(MessageCallback callback, MessageFilterList filterList) { +// callback.handleNewMessage(readMessages(filterList)); +// } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index bb46c32..81513f8 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -1,131 +1,131 @@ -package meerkat.bulletinboard; - -import com.google.common.util.concurrent.*; -import com.google.protobuf.ByteString; -import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; -import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; -import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; -import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Voting; - -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * Created by Arbel Deutsch Peled on 05-Dec-15. - * Thread-based implementation of a Bulletin Board Client. - * Features: - * 1. Handles tasks concurrently. - * 2. Retries submitting - */ -public class ThreadedBulletinBoardClient implements BulletinBoardClient { - - private final static int THREAD_NUM = 10; - ListeningExecutorService listeningExecutor; - - private Digest digest; - - private List meerkatDBs; - private String postSubAddress; - private String readSubAddress; - - private final static int READ_MESSAGES_RETRY_NUM = 1; - - 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(Voting.BulletinBoardClientParams clientParams) { - - meerkatDBs = clientParams.getBulletinBoardAddressList(); - - minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * meerkatDBs.size()); - - listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUM)); - - digest = new SHA256Digest(); - - } - - /** - * Post message to all DBs - * Retry failed DBs - * @param msg is the message, - * @return the message ID for later retrieval - * @throws CommunicationException - */ - @Override - public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback){ - - // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.POST_MESSAGE, msg, -1); - - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new PostMessageFutureCallback(listeningExecutor, callback)); - - // 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 void getRedundancy(MessageID id, ClientCallback callback) { - - // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.GET_REDUNDANCY, id, 1); - - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new GetRedundancyFutureCallback(listeningExecutor, callback)); - - } - - /** - * 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 - */ - @Override - public void readMessages(MessageFilterList filterList, ClientCallback> callback) { - - // Create job - BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.READ_MESSAGES, - filterList, READ_MESSAGES_RETRY_NUM); - - // Submit job and create callback - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new ReadMessagesFutureCallback(listeningExecutor, callback)); - - } - - @Override - public void close() { - try { - listeningExecutor.shutdown(); - while (! listeningExecutor.isShutdown()) { - listeningExecutor.awaitTermination(10, TimeUnit.SECONDS); - } - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - } - -} +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.*; +import com.google.protobuf.ByteString; +import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; +import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; +import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; +import meerkat.comm.CommunicationException; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Voting; + +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + * Thread-based implementation of a Bulletin Board Client. + * Features: + * 1. Handles tasks concurrently. + * 2. Retries submitting + */ +public class ThreadedBulletinBoardClient implements BulletinBoardClient { + + private final static int THREAD_NUM = 10; + ListeningExecutorService listeningExecutor; + + private Digest digest; + + private List meerkatDBs; + private String postSubAddress; + private String readSubAddress; + + private final static int READ_MESSAGES_RETRY_NUM = 1; + + 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(Voting.BulletinBoardClientParams clientParams) { + + meerkatDBs = clientParams.getBulletinBoardAddressList(); + + minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * meerkatDBs.size()); + + listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(THREAD_NUM)); + + digest = new SHA256Digest(); + + } + + /** + * Post message to all DBs + * Retry failed DBs + * @param msg is the message, + * @return the message ID for later retrieval + * @throws CommunicationException + */ + @Override + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback){ + + // Create job + BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.POST_MESSAGE, msg, -1); + + // Submit job and create callback + Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new PostMessageFutureCallback(listeningExecutor, callback)); + + // 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 void getRedundancy(MessageID id, ClientCallback callback) { + + // Create job + BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.GET_REDUNDANCY, id, 1); + + // Submit job and create callback + Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new GetRedundancyFutureCallback(listeningExecutor, callback)); + + } + + /** + * 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 + */ + @Override + public void readMessages(MessageFilterList filterList, ClientCallback> callback) { + + // Create job + BulletinClientJob job = new BulletinClientJob(meerkatDBs, minAbsoluteRedundancy, BulletinClientJob.JobType.READ_MESSAGES, + filterList, READ_MESSAGES_RETRY_NUM); + + // Submit job and create callback + Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), new ReadMessagesFutureCallback(listeningExecutor, callback)); + + } + + @Override + public void close() { + try { + listeningExecutor.shutdown(); + while (! listeningExecutor.isShutdown()) { + listeningExecutor.awaitTermination(10, TimeUnit.SECONDS); + } + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java index 7c5b7b0..d682b38 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java @@ -1,25 +1,25 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinClientJob; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public abstract class ClientFutureCallback implements FutureCallback { - - protected ListeningExecutorService listeningExecutor; - - ClientFutureCallback(ListeningExecutorService listeningExecutor) { - this.listeningExecutor = listeningExecutor; - } - -} +package meerkat.bulletinboard.callbacks; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListeningExecutorService; +import meerkat.bulletinboard.BulletinClientJob; +import meerkat.bulletinboard.BulletinClientJobResult; +import meerkat.bulletinboard.BulletinClientWorker; +import meerkat.protobuf.BulletinBoardAPI; + +import java.util.List; + +/** + * This is a future callback used to listen to workers and run on job finish + * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error + */ +public abstract class ClientFutureCallback implements FutureCallback { + + protected ListeningExecutorService listeningExecutor; + + ClientFutureCallback(ListeningExecutorService listeningExecutor) { + this.listeningExecutor = listeningExecutor; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java index 518ed77..c083623 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java @@ -1,38 +1,38 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class GetRedundancyFutureCallback extends ClientFutureCallback { - - private BulletinBoardClient.ClientCallback callback; - - public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - int absoluteRedundancy = ((IntMsg) result.getResult()).getValue(); - int totalServers = result.getJob().getServerAddresses().size(); - - callback.handleCallback( ((float) absoluteRedundancy) / ((float) totalServers) ); - - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} +package meerkat.bulletinboard.callbacks; + +import com.google.common.util.concurrent.ListeningExecutorService; +import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinClientJobResult; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * This is a future callback used to listen to workers and run on job finish + * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error + */ +public class GetRedundancyFutureCallback extends ClientFutureCallback { + + private BulletinBoardClient.ClientCallback callback; + + public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, + BulletinBoardClient.ClientCallback callback) { + super(listeningExecutor); + this.callback = callback; + } + + @Override + public void onSuccess(BulletinClientJobResult result) { + + int absoluteRedundancy = ((IntMsg) result.getResult()).getValue(); + int totalServers = result.getJob().getServerAddresses().size(); + + callback.handleCallback( ((float) absoluteRedundancy) / ((float) totalServers) ); + + } + + @Override + public void onFailure(Throwable t) { + callback.handleFailure(t); + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java index 221ae1a..71f8ee7 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java @@ -1,46 +1,46 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinClientJob; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class PostMessageFutureCallback extends ClientFutureCallback { - - private BulletinBoardClient.ClientCallback callback; - - public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - BulletinClientJob job = result.getJob(); - - job.decMaxRetry(); - - // If redundancy is below threshold: retry - if (job.getMinServers() > 0 && job.isRetry()) { - Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), this); - } - - callback.handleCallback(null); - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} +package meerkat.bulletinboard.callbacks; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListeningExecutorService; +import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinClientJob; +import meerkat.bulletinboard.BulletinClientJobResult; +import meerkat.bulletinboard.BulletinClientWorker; +import meerkat.protobuf.BulletinBoardAPI; + +import java.util.List; + +/** + * This is a future callback used to listen to workers and run on job finish + * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error + */ +public class PostMessageFutureCallback extends ClientFutureCallback { + + private BulletinBoardClient.ClientCallback callback; + + public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, + BulletinBoardClient.ClientCallback callback) { + super(listeningExecutor); + this.callback = callback; + } + + @Override + public void onSuccess(BulletinClientJobResult result) { + + BulletinClientJob job = result.getJob(); + + job.decMaxRetry(); + + // If redundancy is below threshold: retry + if (job.getMinServers() > 0 && job.isRetry()) { + Futures.addCallback(listeningExecutor.submit(new BulletinClientWorker(job)), this); + } + + callback.handleCallback(null); + } + + @Override + public void onFailure(Throwable t) { + callback.handleFailure(t); + } +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java index 4c43ba2..fe321a4 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java @@ -1,38 +1,38 @@ -package meerkat.bulletinboard.callbacks; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinClientJob; -import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; - -/** - * This is a future callback used to listen to workers and run on job finish - * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error - */ -public class ReadMessagesFutureCallback extends ClientFutureCallback { - - private BulletinBoardClient.ClientCallback> callback; - - public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback> callback) { - super(listeningExecutor); - this.callback = callback; - } - - @Override - public void onSuccess(BulletinClientJobResult result) { - - callback.handleCallback(((BulletinBoardAPI.BulletinBoardMessageList) result.getResult()).getMessageList()); - - } - - @Override - public void onFailure(Throwable t) { - callback.handleFailure(t); - } -} +package meerkat.bulletinboard.callbacks; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListeningExecutorService; +import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinClientJob; +import meerkat.bulletinboard.BulletinClientJobResult; +import meerkat.bulletinboard.BulletinClientWorker; +import meerkat.protobuf.BulletinBoardAPI; + +import java.util.List; + +/** + * This is a future callback used to listen to workers and run on job finish + * Depending on the type of job and the finishing status of the worker: a decision is made whether to retry or return an error + */ +public class ReadMessagesFutureCallback extends ClientFutureCallback { + + private BulletinBoardClient.ClientCallback> callback; + + public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, + BulletinBoardClient.ClientCallback> callback) { + super(listeningExecutor); + this.callback = callback; + } + + @Override + public void onSuccess(BulletinClientJobResult result) { + + callback.handleCallback(((BulletinBoardAPI.BulletinBoardMessageList) result.getResult()).getMessageList()); + + } + + @Override + public void onFailure(Throwable t) { + callback.handleFailure(t); + } +} diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index dda76c7..b993f1f 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -1,214 +1,214 @@ -import com.google.protobuf.ByteString; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; -import meerkat.bulletinboard.ThreadedBulletinBoardClient; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Crypto; - -import meerkat.protobuf.Voting.*; -import meerkat.util.BulletinBoardMessageComparator; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.number.OrderingComparison.*; - -import java.util.*; -import java.util.concurrent.Semaphore; - -/** - * Created by Arbel Deutsch Peled on 05-Dec-15. - */ -public class BulletinBoardClientIntegrationTest { - - Semaphore jobSemaphore; - Vector thrown; - - private class PostCallback implements ClientCallback{ - - @Override - public void handleCallback(Object msg) { - System.err.println("Post operation completed"); - jobSemaphore.release(); - } - - @Override - public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); - } - } - - private class RedundancyCallback implements ClientCallback{ - - private float minRedundancy; - - public RedundancyCallback(float minRedundancy) { - this.minRedundancy = minRedundancy; - } - - @Override - public void handleCallback(Float redundancy) { - System.err.println("Redundancy found is: " + redundancy); - jobSemaphore.release(); - assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); - } - - @Override - public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); - } - } - - private class ReadCallback implements ClientCallback>{ - - private List expectedMsgList; - - public ReadCallback(List expectedMsgList) { - this.expectedMsgList = expectedMsgList; - } - - @Override - public void handleCallback(List messages) { - - System.err.println(messages); - jobSemaphore.release(); - - BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); - - assertThat(messages.size(), is(expectedMsgList.size())); - - Iterator expectedMessageIterator = expectedMsgList.iterator(); - Iterator receivedMessageIterator = messages.iterator(); - - while (expectedMessageIterator.hasNext()) { - assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); - } - - } - - @Override - public void handleFailure(Throwable t) { - thrown.add(t); - jobSemaphore.release(); - } - } - - private BulletinBoardClient bulletinBoardClient; - - private PostCallback postCallback; - private RedundancyCallback redundancyCallback; - private ReadCallback readCallback; - - 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); - - @Before - public void init(){ - - bulletinBoardClient = new ThreadedBulletinBoardClient(); - - List testDB = new LinkedList(); - testDB.add(BASE_URL); - - bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() - .addBulletinBoardAddress("http://localhost:8081") - .setMinRedundancy((float) 1.0) - .build()); - - postCallback = new PostCallback(); - redundancyCallback = new RedundancyCallback((float) 1.0); - - thrown = new Vector<>(); - jobSemaphore = new Semaphore(0); - - } - - @Test - public void postTest() { - - 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}; - - BulletinBoardMessage msg; - - MessageFilterList filterList; - List msgList; - - MessageID messageID; - - Comparator msgComparator = new BulletinBoardMessageComparator(); - - msg = BulletinBoardMessage.newBuilder() - .setMsg(UnsignedBulletinBoardMessage.newBuilder() - .addTag("Signature") - .addTag("Trustee") - .setData(ByteString.copyFrom(b1)) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.DSA) - .setData(ByteString.copyFrom(b2)) - .setSignerId(ByteString.copyFrom(b3)) - .build()) - .addSig(Crypto.Signature.newBuilder() - .setType(Crypto.SignatureType.ECDSA) - .setData(ByteString.copyFrom(b3)) - .setSignerId(ByteString.copyFrom(b2)) - .build()) - .build(); - - messageID = bulletinBoardClient.postMessage(msg,postCallback); - - try { - jobSemaphore.acquire(); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - bulletinBoardClient.getRedundancy(messageID,redundancyCallback); - - filterList = MessageFilterList.newBuilder() - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Signature") - .build() - ) - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Trustee") - .build() - ) - .build(); - - msgList = new LinkedList(); - msgList.add(msg); - - readCallback = new ReadCallback(msgList); - - bulletinBoardClient.readMessages(filterList, readCallback); - try { - jobSemaphore.acquire(2); - } catch (InterruptedException e) { - System.err.println(e.getCause() + " " + e.getMessage()); - } - - bulletinBoardClient.close(); - - for (Throwable t : thrown) { - System.err.println(t.getMessage()); - } - if (thrown.size() > 0) { - assert false; - } - - } - -} +import com.google.protobuf.ByteString; +import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.ThreadedBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; + +import meerkat.protobuf.Voting.*; +import meerkat.util.BulletinBoardMessageComparator; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.number.OrderingComparison.*; + +import java.util.*; +import java.util.concurrent.Semaphore; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class BulletinBoardClientIntegrationTest { + + Semaphore jobSemaphore; + Vector thrown; + + private class PostCallback implements ClientCallback{ + + @Override + public void handleCallback(Object msg) { + System.err.println("Post operation completed"); + jobSemaphore.release(); + } + + @Override + public void handleFailure(Throwable t) { + thrown.add(t); + jobSemaphore.release(); + } + } + + private class RedundancyCallback implements ClientCallback{ + + private float minRedundancy; + + public RedundancyCallback(float minRedundancy) { + this.minRedundancy = minRedundancy; + } + + @Override + public void handleCallback(Float redundancy) { + System.err.println("Redundancy found is: " + redundancy); + jobSemaphore.release(); + assertThat(redundancy, greaterThanOrEqualTo(minRedundancy)); + } + + @Override + public void handleFailure(Throwable t) { + thrown.add(t); + jobSemaphore.release(); + } + } + + private class ReadCallback implements ClientCallback>{ + + private List expectedMsgList; + + public ReadCallback(List expectedMsgList) { + this.expectedMsgList = expectedMsgList; + } + + @Override + public void handleCallback(List messages) { + + System.err.println(messages); + jobSemaphore.release(); + + BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); + + assertThat(messages.size(), is(expectedMsgList.size())); + + Iterator expectedMessageIterator = expectedMsgList.iterator(); + Iterator receivedMessageIterator = messages.iterator(); + + while (expectedMessageIterator.hasNext()) { + assertThat(msgComparator.compare(expectedMessageIterator.next(), receivedMessageIterator.next()), is(0)); + } + + } + + @Override + public void handleFailure(Throwable t) { + thrown.add(t); + jobSemaphore.release(); + } + } + + private BulletinBoardClient bulletinBoardClient; + + private PostCallback postCallback; + private RedundancyCallback redundancyCallback; + private ReadCallback readCallback; + + 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); + + @Before + public void init(){ + + bulletinBoardClient = new ThreadedBulletinBoardClient(); + + List testDB = new LinkedList(); + testDB.add(BASE_URL); + + bulletinBoardClient.init(BulletinBoardClientParams.newBuilder() + .addBulletinBoardAddress("http://localhost:8081") + .setMinRedundancy((float) 1.0) + .build()); + + postCallback = new PostCallback(); + redundancyCallback = new RedundancyCallback((float) 1.0); + + thrown = new Vector<>(); + jobSemaphore = new Semaphore(0); + + } + + @Test + public void postTest() { + + 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}; + + BulletinBoardMessage msg; + + MessageFilterList filterList; + List msgList; + + MessageID messageID; + + Comparator msgComparator = new BulletinBoardMessageComparator(); + + msg = BulletinBoardMessage.newBuilder() + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .addTag("Signature") + .addTag("Trustee") + .setData(ByteString.copyFrom(b1)) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.DSA) + .setData(ByteString.copyFrom(b2)) + .setSignerId(ByteString.copyFrom(b3)) + .build()) + .addSig(Crypto.Signature.newBuilder() + .setType(Crypto.SignatureType.ECDSA) + .setData(ByteString.copyFrom(b3)) + .setSignerId(ByteString.copyFrom(b2)) + .build()) + .build(); + + messageID = bulletinBoardClient.postMessage(msg,postCallback); + + try { + jobSemaphore.acquire(); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + bulletinBoardClient.getRedundancy(messageID,redundancyCallback); + + filterList = MessageFilterList.newBuilder() + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Signature") + .build() + ) + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Trustee") + .build() + ) + .build(); + + msgList = new LinkedList(); + msgList.add(msg); + + readCallback = new ReadCallback(msgList); + + bulletinBoardClient.readMessages(filterList, readCallback); + try { + jobSemaphore.acquire(2); + } catch (InterruptedException e) { + System.err.println(e.getCause() + " " + e.getMessage()); + } + + bulletinBoardClient.close(); + + for (Throwable t : thrown) { + System.err.println(t.getMessage()); + } + if (thrown.size() > 0) { + assert false; + } + + } + +} diff --git a/bulletin-board-server/.gitignore b/bulletin-board-server/.gitignore index ae3c172..3e2fcc7 100644 --- a/bulletin-board-server/.gitignore +++ b/bulletin-board-server/.gitignore @@ -1 +1 @@ -/bin/ +/bin/ diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 0bc5452..772fb14 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -1,241 +1,241 @@ - -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.7.+' - 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 dbTest(type: Test) { - include '**/*H2*Test*' - include '**/*MySql*Test' -} - -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.7.+' + 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 dbTest(type: Test) { + include '**/*H2*Test*' + include '**/*MySql*Test' +} + +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 + } + } + } +} + + + diff --git a/bulletin-board-server/gradle-app.setting b/bulletin-board-server/gradle-app.setting index b0bad25..21226bc 100644 --- a/bulletin-board-server/gradle-app.setting +++ b/bulletin-board-server/gradle-app.setting @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/service/HelloProtoBuf.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/service/HelloProtoBuf.java index 772e7dd..c1f5de8 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/service/HelloProtoBuf.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/service/HelloProtoBuf.java @@ -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 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 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(); + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 52bf42b..8402e55 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,484 +1,484 @@ -package meerkat.bulletinboard.sqlserver; - -import java.sql.*; -import java.util.*; - -import com.google.protobuf.ProtocolStringList; - -import meerkat.bulletinboard.BulletinBoardServer; -import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper; -import meerkat.bulletinboard.sqlserver.mappers.MessageMapper; -import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper; -import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Crypto.Signature; -import meerkat.protobuf.Crypto.SignatureVerificationKey; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; - -import javax.sql.DataSource; - -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; - -/** - * This is a generic SQL implementation of the BulletinBoardServer API. - */ -public class BulletinBoardSQLServer implements BulletinBoardServer{ - - /** - * This interface provides the required implementation-specific data to enable an access to an actual SQL server. - * It accounts for differences in languages between SQL DB types and for the different addresses needed to access them. - */ - public interface SQLQueryProvider { - - /** - * Allowed query types. - * Note that each query returned has to comply with the parameter names specified ny getParamNames - */ - public static enum QueryType { - - FIND_MSG_ID(new String[] {"MsgId"}), - INSERT_MSG(new String[] {"MsgId","Msg"}), - INSERT_NEW_TAG(new String[] {"Tag"}), - CONNECT_TAG(new String[] {"EntryNum","Tag"}), - ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), - GET_SIGNATURES(new String[] {"EntryNum"}), - GET_MESSAGES(new String[] {}); - - private String[] paramNames; - - private QueryType(String[] paramNames) { - this.paramNames = paramNames; - } - - public String[] getParamNames() { - return paramNames; - } - - } - - /** - * This enum provides the standard translation between a filter type and the corresponding parameter name in the SQL query - */ - public static enum FilterTypeParam { - - ENTRY_NUM("EntryNum", Types.INTEGER), - MSG_ID("MsgId", Types.BLOB), - SIGNER_ID("SignerId", Types.BLOB), - TAG("Tag", Types.VARCHAR), - LIMIT("Limit", Types.INTEGER); - - private FilterTypeParam(String paramName, int paramType) { - this.paramName = paramName; - this.paramType = paramType; - } - - private String paramName; - private int paramType; - - public static FilterTypeParam getFilterTypeParamName(FilterType filterType) { - switch (filterType) { - - case MSG_ID: - return MSG_ID; - - case EXACT_ENTRY: // Go through - case MAX_ENTRY: - return ENTRY_NUM; - - case SIGNER_ID: - return SIGNER_ID; - - case TAG: - return TAG; - - case MAX_MESSAGES: - return LIMIT; - - default: - return null; - } - } - - public String getParamName() { - return paramName; - } - - public int getParamType() { - return paramType; - } - } - - /** - * This function translates a QueryType into an actual SQL query. - * @param queryType is the type of query requested - * @return a string representation of the query for the specific type of SQL database implemented. - */ - public String getSQLString(QueryType queryType) throws IllegalArgumentException; - - /** - * Used to retrieve a condition to add to an SQL statement that will make the result comply with the filter type - * @param filterType is the filter type - * @param serialNum is a unique number used to identify the condition variables from other condition instances - * @return The SQL string for the condition - * @throws IllegalArgumentException if the filter type used is not supported - */ - public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException; - - public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException; - - /** - * @return the string needed in order to connect to the DB. - */ - public DataSource getDataSource(); - - /** - * This is used to get a list of queries that together create the schema needed for the DB. - * Note that these queries should not assume anything about the current state of the DB. - * In particular: they should not erase any existing tables and/or entries. - * @return The list of queries. - */ - public List getSchemaCreationCommands(); - - /** - * This is used to get a list of queries that together delete the schema needed for the DB. - * This is useful primarily for tests, in which we want to make sure we start with a clean DB. - * @return The list of queries. - */ - public List getSchemaDeletionCommands(); - - } - - private Object getParam(MessageFilter messageFilter) { - - switch (messageFilter.getType()) { - - case MSG_ID: // Go through - case SIGNER_ID: - return messageFilter.getId().toByteArray(); - - case EXACT_ENTRY: // Go through - case MAX_ENTRY: - return messageFilter.getEntry(); - - case TAG: - return messageFilter.getTag(); - - case MAX_MESSAGES: - return messageFilter.getMaxMessages(); - - default: - return null; - } - - } - - /** - * This class implements a comparator for the MessageFilter class - * The comparison is done solely by comparing the type of the filter - * This is used to sort the filters by type - */ - public class FilterTypeComparator implements Comparator { - - @Override - public int compare(MessageFilter filter1, MessageFilter filter2) { - return filter1.getTypeValue() - filter2.getTypeValue(); - } - } - - protected SQLQueryProvider sqlQueryProvider; - - protected NamedParameterJdbcTemplate jdbcTemplate; - - protected Digest digest; - - protected List trusteeSignatureVerificationArray; - protected int minTrusteeSignatures; - - protected List> pollingCommitteeSignatureVerificationKeyArray; - protected int minCommiteeSignatures; - - /** - * This constructor sets the type of SQL language in use. - * @param sqlQueryProvider is the provider of the SQL query strings required for actual operation of the server. - */ - public BulletinBoardSQLServer(SQLQueryProvider sqlQueryProvider) { - this.sqlQueryProvider = sqlQueryProvider; - } - - /** - * This method creates the schema in the given DB to prepare for future transactions - * It does not assume anything about the current state of the database - * @throws SQLException - */ - private void createSchema() throws SQLException { - - final int TIMEOUT = 20; - - for (String command : sqlQueryProvider.getSchemaCreationCommands()) { - jdbcTemplate.update(command,(Map) null); - } - - } - - /** - * This method initializes the signatures, connects to the DB and creates the schema (if required). - */ - @Override - public void init(String meerkatDB) throws CommunicationException { - // TODO write signature reading part. - - digest = new SHA256Digest(); - - jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); - - try { - createSchema(); - } catch (SQLException e) { - throw new CommunicationException("Couldn't create schema " + e.getMessage()); - } - - } - - /** - * This method verifies the authenticity of the received message based on - * the stored signatures. - * - * @param msg - * is the message to authenticate (containing the signature). - * @return TRUE if the message is authenticated and FALSE otherwise. - */ - private boolean verifyMessage(BulletinBoardMessage msg) { - //TODO: Replace with actual verification. - return true; - } - - /** - * This procedure makes sure that all tags in the given list have an entry in the tags table. - * @param tags - */ - protected void insertNewTags(String[] tags) throws SQLException { - - String sql; - - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); - Map namedParameters[] = new HashMap[tags.length]; - - for (int i = 0 ; i < tags.length ; i++){ - namedParameters[i] = new HashMap(); - namedParameters[i].put("Tag", tags[i]); - } - - jdbcTemplate.batchUpdate(sql, namedParameters); - - } - - /** - * This procedure is used to convert a boolean to a BoolMsg. - * @param b is the boolean to convert. - * @return a ProtoBuf message with boolean payload. - */ - private BoolMsg boolToBoolMsg(boolean b){ - return BoolMsg.newBuilder() - .setValue(b) - .build(); - } - - @Override - public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { - - if (!verifyMessage(msg)) { - return boolToBoolMsg(false); - } - - String sql; - Map[] namedParameterArray; - - byte[] msgID; - long entryNum; - - ProtocolStringList tagList; - String[] tags; - - List signatureList; - Signature[] signatures; - - // Calculate message ID (depending only on the the unsigned message) - - digest.reset(); - digest.update(msg.getMsg()); - - msgID = digest.digest(); - - // Add message to table if needed and store entry number of message. - - - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); - Map namedParameters = new HashMap(); - namedParameters.put("MsgId",msgID); - - List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper()); - - if (entryNums.size() > 0){ - - entryNum = entryNums.get(0); - - } else{ - - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); - namedParameters.put("Msg", msg.getMsg().toByteArray()); - - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); - - entryNum = keyHolder.getKey().longValue(); - - } - - // Retrieve tags and store new ones in tag table. - - try { - - tagList = msg.getMsg().getTagList(); - tags = new String[tagList.size()]; - tags = tagList.toArray(tags); - - insertNewTags(tags); - - } catch (SQLException e) { - throw new CommunicationException(e.getMessage()); - } - - // Connect message to tags. - - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); - - namedParameterArray = new HashMap[tags.length]; - - for (int i = 0 ; i < tags.length ; i++) { - namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("Tag", tags[i]); - } - - jdbcTemplate.batchUpdate(sql, namedParameterArray); - - // Retrieve signatures. - - signatureList = msg.getSigList(); - signatures = new Signature[signatureList.size()]; - signatures = signatureList.toArray(signatures); - - // Connect message to signatures. - - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); - - namedParameterArray = new HashMap[signatures.length]; - - for (int i = 0 ; i < signatures.length ; i++) { - namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray()); - namedParameterArray[i].put("Signature", signatures[i].toByteArray()); - } - - jdbcTemplate.batchUpdate(sql,namedParameterArray); - - return boolToBoolMsg(true); - } - - @Override - public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { - - BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); - - // SQL length is roughly 50 characters per filter + 50 for the query itself - StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); - - MapSqlParameterSource namedParameters; - int paramNum; - - MessageMapper messageMapper = new MessageMapper(); - SignatureMapper signatureMapper = new SignatureMapper(); - - List filters = new ArrayList(filterList.getFilterList()); - - boolean isFirstFilter = true; - - Collections.sort(filters, new FilterTypeComparator()); - - // Check if Tag/Signature tables are required for filtering purposes - - sqlBuilder.append(sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES)); - // Add conditions - - namedParameters = new MapSqlParameterSource(); - - if (!filters.isEmpty()) { - sqlBuilder.append(" WHERE "); - - for (paramNum = 0 ; paramNum < filters.size() ; paramNum++) { - - MessageFilter filter = filters.get(paramNum); - - if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE) { - if (isFirstFilter) { - isFirstFilter = false; - } else { - sqlBuilder.append(" AND "); - } - } - - sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); - - SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType()); - - namedParameters.addValue( - filterTypeParam.getParamName() + Integer.toString(paramNum), - getParam(filter), - filterTypeParam.getParamType(), - sqlQueryProvider.getConditionParamTypeName(filter.getType())); - - } - - } - - // Run query - - List msgBuilders = jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper); - - // Compile list of messages - - for (BulletinBoardMessage.Builder msgBuilder : msgBuilders) { - - // Retrieve signatures - - namedParameters = new MapSqlParameterSource(); - namedParameters.addValue("EntryNum", msgBuilder.getEntryNum()); - - List signatures = jdbcTemplate.query( - sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES), - namedParameters, - signatureMapper); - - // Append signatures - msgBuilder.addAllSig(signatures); - - // Finalize message and add to message list. - - resultListBuilder.addMessage(msgBuilder.build()); - - } - - //Combine results and return. - return resultListBuilder.build(); - - } - - @Override - public void close() {} - -} +package meerkat.bulletinboard.sqlserver; + +import java.sql.*; +import java.util.*; + +import com.google.protobuf.ProtocolStringList; + +import meerkat.bulletinboard.BulletinBoardServer; +import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper; +import meerkat.bulletinboard.sqlserver.mappers.MessageMapper; +import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.Signature; +import meerkat.protobuf.Crypto.SignatureVerificationKey; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; + +/** + * This is a generic SQL implementation of the BulletinBoardServer API. + */ +public class BulletinBoardSQLServer implements BulletinBoardServer{ + + /** + * This interface provides the required implementation-specific data to enable an access to an actual SQL server. + * It accounts for differences in languages between SQL DB types and for the different addresses needed to access them. + */ + public interface SQLQueryProvider { + + /** + * Allowed query types. + * Note that each query returned has to comply with the parameter names specified ny getParamNames + */ + public static enum QueryType { + + FIND_MSG_ID(new String[] {"MsgId"}), + INSERT_MSG(new String[] {"MsgId","Msg"}), + INSERT_NEW_TAG(new String[] {"Tag"}), + CONNECT_TAG(new String[] {"EntryNum","Tag"}), + ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), + GET_SIGNATURES(new String[] {"EntryNum"}), + GET_MESSAGES(new String[] {}); + + private String[] paramNames; + + private QueryType(String[] paramNames) { + this.paramNames = paramNames; + } + + public String[] getParamNames() { + return paramNames; + } + + } + + /** + * This enum provides the standard translation between a filter type and the corresponding parameter name in the SQL query + */ + public static enum FilterTypeParam { + + ENTRY_NUM("EntryNum", Types.INTEGER), + MSG_ID("MsgId", Types.BLOB), + SIGNER_ID("SignerId", Types.BLOB), + TAG("Tag", Types.VARCHAR), + LIMIT("Limit", Types.INTEGER); + + private FilterTypeParam(String paramName, int paramType) { + this.paramName = paramName; + this.paramType = paramType; + } + + private String paramName; + private int paramType; + + public static FilterTypeParam getFilterTypeParamName(FilterType filterType) { + switch (filterType) { + + case MSG_ID: + return MSG_ID; + + case EXACT_ENTRY: // Go through + case MAX_ENTRY: + return ENTRY_NUM; + + case SIGNER_ID: + return SIGNER_ID; + + case TAG: + return TAG; + + case MAX_MESSAGES: + return LIMIT; + + default: + return null; + } + } + + public String getParamName() { + return paramName; + } + + public int getParamType() { + return paramType; + } + } + + /** + * This function translates a QueryType into an actual SQL query. + * @param queryType is the type of query requested + * @return a string representation of the query for the specific type of SQL database implemented. + */ + public String getSQLString(QueryType queryType) throws IllegalArgumentException; + + /** + * Used to retrieve a condition to add to an SQL statement that will make the result comply with the filter type + * @param filterType is the filter type + * @param serialNum is a unique number used to identify the condition variables from other condition instances + * @return The SQL string for the condition + * @throws IllegalArgumentException if the filter type used is not supported + */ + public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException; + + public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException; + + /** + * @return the string needed in order to connect to the DB. + */ + public DataSource getDataSource(); + + /** + * This is used to get a list of queries that together create the schema needed for the DB. + * Note that these queries should not assume anything about the current state of the DB. + * In particular: they should not erase any existing tables and/or entries. + * @return The list of queries. + */ + public List getSchemaCreationCommands(); + + /** + * This is used to get a list of queries that together delete the schema needed for the DB. + * This is useful primarily for tests, in which we want to make sure we start with a clean DB. + * @return The list of queries. + */ + public List getSchemaDeletionCommands(); + + } + + private Object getParam(MessageFilter messageFilter) { + + switch (messageFilter.getType()) { + + case MSG_ID: // Go through + case SIGNER_ID: + return messageFilter.getId().toByteArray(); + + case EXACT_ENTRY: // Go through + case MAX_ENTRY: + return messageFilter.getEntry(); + + case TAG: + return messageFilter.getTag(); + + case MAX_MESSAGES: + return messageFilter.getMaxMessages(); + + default: + return null; + } + + } + + /** + * This class implements a comparator for the MessageFilter class + * The comparison is done solely by comparing the type of the filter + * This is used to sort the filters by type + */ + public class FilterTypeComparator implements Comparator { + + @Override + public int compare(MessageFilter filter1, MessageFilter filter2) { + return filter1.getTypeValue() - filter2.getTypeValue(); + } + } + + protected SQLQueryProvider sqlQueryProvider; + + protected NamedParameterJdbcTemplate jdbcTemplate; + + protected Digest digest; + + protected List trusteeSignatureVerificationArray; + protected int minTrusteeSignatures; + + protected List> pollingCommitteeSignatureVerificationKeyArray; + protected int minCommiteeSignatures; + + /** + * This constructor sets the type of SQL language in use. + * @param sqlQueryProvider is the provider of the SQL query strings required for actual operation of the server. + */ + public BulletinBoardSQLServer(SQLQueryProvider sqlQueryProvider) { + this.sqlQueryProvider = sqlQueryProvider; + } + + /** + * This method creates the schema in the given DB to prepare for future transactions + * It does not assume anything about the current state of the database + * @throws SQLException + */ + private void createSchema() throws SQLException { + + final int TIMEOUT = 20; + + for (String command : sqlQueryProvider.getSchemaCreationCommands()) { + jdbcTemplate.update(command,(Map) null); + } + + } + + /** + * This method initializes the signatures, connects to the DB and creates the schema (if required). + */ + @Override + public void init(String meerkatDB) throws CommunicationException { + // TODO write signature reading part. + + digest = new SHA256Digest(); + + jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); + + try { + createSchema(); + } catch (SQLException e) { + throw new CommunicationException("Couldn't create schema " + e.getMessage()); + } + + } + + /** + * This method verifies the authenticity of the received message based on + * the stored signatures. + * + * @param msg + * is the message to authenticate (containing the signature). + * @return TRUE if the message is authenticated and FALSE otherwise. + */ + private boolean verifyMessage(BulletinBoardMessage msg) { + //TODO: Replace with actual verification. + return true; + } + + /** + * This procedure makes sure that all tags in the given list have an entry in the tags table. + * @param tags + */ + protected void insertNewTags(String[] tags) throws SQLException { + + String sql; + + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); + Map namedParameters[] = new HashMap[tags.length]; + + for (int i = 0 ; i < tags.length ; i++){ + namedParameters[i] = new HashMap(); + namedParameters[i].put("Tag", tags[i]); + } + + jdbcTemplate.batchUpdate(sql, namedParameters); + + } + + /** + * This procedure is used to convert a boolean to a BoolMsg. + * @param b is the boolean to convert. + * @return a ProtoBuf message with boolean payload. + */ + private BoolMsg boolToBoolMsg(boolean b){ + return BoolMsg.newBuilder() + .setValue(b) + .build(); + } + + @Override + public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { + + if (!verifyMessage(msg)) { + return boolToBoolMsg(false); + } + + String sql; + Map[] namedParameterArray; + + byte[] msgID; + long entryNum; + + ProtocolStringList tagList; + String[] tags; + + List signatureList; + Signature[] signatures; + + // Calculate message ID (depending only on the the unsigned message) + + digest.reset(); + digest.update(msg.getMsg()); + + msgID = digest.digest(); + + // Add message to table if needed and store entry number of message. + + + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); + Map namedParameters = new HashMap(); + namedParameters.put("MsgId",msgID); + + List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper()); + + if (entryNums.size() > 0){ + + entryNum = entryNums.get(0); + + } else{ + + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); + namedParameters.put("Msg", msg.getMsg().toByteArray()); + + KeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); + + entryNum = keyHolder.getKey().longValue(); + + } + + // Retrieve tags and store new ones in tag table. + + try { + + tagList = msg.getMsg().getTagList(); + tags = new String[tagList.size()]; + tags = tagList.toArray(tags); + + insertNewTags(tags); + + } catch (SQLException e) { + throw new CommunicationException(e.getMessage()); + } + + // Connect message to tags. + + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); + + namedParameterArray = new HashMap[tags.length]; + + for (int i = 0 ; i < tags.length ; i++) { + namedParameterArray[i] = new HashMap(); + namedParameterArray[i].put("EntryNum", entryNum); + namedParameterArray[i].put("Tag", tags[i]); + } + + jdbcTemplate.batchUpdate(sql, namedParameterArray); + + // Retrieve signatures. + + signatureList = msg.getSigList(); + signatures = new Signature[signatureList.size()]; + signatures = signatureList.toArray(signatures); + + // Connect message to signatures. + + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); + + namedParameterArray = new HashMap[signatures.length]; + + for (int i = 0 ; i < signatures.length ; i++) { + namedParameterArray[i] = new HashMap(); + namedParameterArray[i].put("EntryNum", entryNum); + namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray()); + namedParameterArray[i].put("Signature", signatures[i].toByteArray()); + } + + jdbcTemplate.batchUpdate(sql,namedParameterArray); + + return boolToBoolMsg(true); + } + + @Override + public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { + + BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); + + // SQL length is roughly 50 characters per filter + 50 for the query itself + StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); + + MapSqlParameterSource namedParameters; + int paramNum; + + MessageMapper messageMapper = new MessageMapper(); + SignatureMapper signatureMapper = new SignatureMapper(); + + List filters = new ArrayList(filterList.getFilterList()); + + boolean isFirstFilter = true; + + Collections.sort(filters, new FilterTypeComparator()); + + // Check if Tag/Signature tables are required for filtering purposes + + sqlBuilder.append(sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES)); + // Add conditions + + namedParameters = new MapSqlParameterSource(); + + if (!filters.isEmpty()) { + sqlBuilder.append(" WHERE "); + + for (paramNum = 0 ; paramNum < filters.size() ; paramNum++) { + + MessageFilter filter = filters.get(paramNum); + + if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE) { + if (isFirstFilter) { + isFirstFilter = false; + } else { + sqlBuilder.append(" AND "); + } + } + + sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); + + SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType()); + + namedParameters.addValue( + filterTypeParam.getParamName() + Integer.toString(paramNum), + getParam(filter), + filterTypeParam.getParamType(), + sqlQueryProvider.getConditionParamTypeName(filter.getType())); + + } + + } + + // Run query + + List msgBuilders = jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper); + + // Compile list of messages + + for (BulletinBoardMessage.Builder msgBuilder : msgBuilders) { + + // Retrieve signatures + + namedParameters = new MapSqlParameterSource(); + namedParameters.addValue("EntryNum", msgBuilder.getEntryNum()); + + List signatures = jdbcTemplate.query( + sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES), + namedParameters, + signatureMapper); + + // Append signatures + msgBuilder.addAllSig(signatures); + + // Finalize message and add to message list. + + resultListBuilder.addMessage(msgBuilder.build()); + + } + + //Combine results and return. + return resultListBuilder.build(); + + } + + @Override + public void close() {} + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index fa2b146..11dcefe 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -1,164 +1,164 @@ -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.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 GET_MESSAGES: - return "SELECT MsgTable.EntryNum, MsgTable.Msg 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)"; - - 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 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)"; - 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 MAX_MESSAGES: - return "INT"; - - case MSG_ID: // Go through - case SIGNER_ID: - return "TINYBLOB"; - - case TAG: - return "VARCHAR"; - - 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 getSchemaCreationCommands() { - List list = new LinkedList(); - - list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, 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)"); - - // 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 getSchemaDeletionCommands() { - List list = new LinkedList(); - - list.add("DROP TABLE IF EXISTS UtilityTable"); - 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.h2.jdbcx.JdbcDataSource; +import javax.naming.Context; +import javax.naming.InitialContext; + +import javax.naming.NamingException; +import javax.sql.DataSource; +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 GET_MESSAGES: + return "SELECT MsgTable.EntryNum, MsgTable.Msg 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)"; + + 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 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)"; + 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 MAX_MESSAGES: + return "INT"; + + case MSG_ID: // Go through + case SIGNER_ID: + return "TINYBLOB"; + + case TAG: + return "VARCHAR"; + + 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 getSchemaCreationCommands() { + List list = new LinkedList(); + + list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, 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)"); + + // 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 getSchemaDeletionCommands() { + List list = new LinkedList(); + + list.add("DROP TABLE IF EXISTS UtilityTable"); + 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; + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index c00c044..53d9829 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -1,148 +1,148 @@ -package meerkat.bulletinboard.sqlserver; - -import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; -import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider; -import meerkat.protobuf.BulletinBoardAPI.FilterType; - -import javax.sql.DataSource; -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 "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum, :SignerId, :Signature)"; - case CONNECT_TAG: - return "INSERT 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 GET_MESSAGES: - return "SELECT MsgTable.EntryNum, MsgTable.Msg 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 IGNORE INTO TagTable(Tag) VALUES (:Tag)"; - 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 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)"; - 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 MAX_MESSAGES: - return "INT"; - - case MSG_ID: // Go through - case SIGNER_ID: - return "TINYBLOB"; - - case TAG: - return "VARCHAR"; - - 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); - - return dataSource; - } - - @Override - public List getSchemaCreationCommands() { - List list = new LinkedList(); - - list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB, 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 Uni UNIQUE(SignerId(32), EntryNum), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); - - return list; - } - - @Override - public List getSchemaDeletionCommands() { - List list = new LinkedList(); - - 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.sqlserver.BulletinBoardSQLServer.SQLQueryProvider; +import meerkat.protobuf.BulletinBoardAPI.FilterType; + +import javax.sql.DataSource; +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 "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum, :SignerId, :Signature)"; + case CONNECT_TAG: + return "INSERT 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 GET_MESSAGES: + return "SELECT MsgTable.EntryNum, MsgTable.Msg 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 IGNORE INTO TagTable(Tag) VALUES (:Tag)"; + 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 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)"; + 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 MAX_MESSAGES: + return "INT"; + + case MSG_ID: // Go through + case SIGNER_ID: + return "TINYBLOB"; + + case TAG: + return "VARCHAR"; + + 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); + + return dataSource; + } + + @Override + public List getSchemaCreationCommands() { + List list = new LinkedList(); + + list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB, 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 Uni UNIQUE(SignerId(32), EntryNum), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + + return list; + } + + @Override + public List getSchemaDeletionCommands() { + List list = new LinkedList(); + + 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; + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index 945ae47..089bdd2 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -1,123 +1,123 @@ -package meerkat.bulletinboard.sqlserver; - -import meerkat.protobuf.BulletinBoardAPI.*; -import org.sqlite.SQLiteDataSource; - -import javax.sql.DataSource; -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 GET_MESSAGES: - return "SELECT MsgTable.EntryNum, MsgTable.Msg 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)"; - 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 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)"; - default: - throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); - } - - } - - @Override - public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException { - return null; //TODO: write this. - } - - @Override - public DataSource getDataSource() { - // TODO: Fix this - SQLiteDataSource dataSource = new SQLiteDataSource(); - dataSource.setUrl("jdbc:sqlite:" + dbName); - dataSource.setDatabaseName("meerkat"); //TODO: Make generic - - return dataSource; - } - - - @Override - public List getSchemaCreationCommands() { - List list = new LinkedList(); - - 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))"); - - list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); - list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)"); - - return list; - } - - @Override - public List getSchemaDeletionCommands() { - List list = new LinkedList(); - - 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.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 GET_MESSAGES: + return "SELECT MsgTable.EntryNum, MsgTable.Msg 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)"; + 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 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)"; + default: + throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); + } + + } + + @Override + public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException { + return null; //TODO: write this. + } + + @Override + public DataSource getDataSource() { + // TODO: Fix this + SQLiteDataSource dataSource = new SQLiteDataSource(); + dataSource.setUrl("jdbc:sqlite:" + dbName); + dataSource.setDatabaseName("meerkat"); //TODO: Make generic + + return dataSource; + } + + + @Override + public List getSchemaCreationCommands() { + List list = new LinkedList(); + + 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))"); + + list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); + list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)"); + + return list; + } + + @Override + public List getSchemaDeletionCommands() { + List list = new LinkedList(); + + 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; + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java index 478c39e..68addbc 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java @@ -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 EntryNumMapper implements RowMapper { - - @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 EntryNumMapper implements RowMapper { + + @Override + public Long mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getLong(1); + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageMapper.java index fdc1fa8..d1584aa 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageMapper.java @@ -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 { - - @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 { + + @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; + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/SignatureMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/SignatureMapper.java index 60015c1..95ff087 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/SignatureMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/SignatureMapper.java @@ -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 { - - @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 { + + @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); + } + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index b3fc03c..1ab4a62 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -1,124 +1,124 @@ -package meerkat.bulletinboard.webapp; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; - -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.protobuf.BulletinBoardAPI.BoolMsg; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; -import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; -import meerkat.rest.Constants; - -@Path(Constants.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(Constants.POST_MESSAGE_PATH) - @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) - @Override - public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { - init(); - return bulletinBoard.postMessage(msg); - } - - @Path(Constants.READ_MESSAGES_PATH) - @POST - @Consumes(Constants.MEDIATYPE_PROTOBUF) - @Produces(Constants.MEDIATYPE_PROTOBUF) - @Override - public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { - init(); - return bulletinBoard.readMessages(filterList); - } - - @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.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +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.protobuf.BulletinBoardAPI.BoolMsg; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; +import meerkat.rest.Constants; + +@Path(Constants.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(Constants.POST_MESSAGE_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { + init(); + return bulletinBoard.postMessage(msg); + } + + @Path(Constants.READ_MESSAGES_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { + init(); + return bulletinBoard.readMessages(filterList); + } + + @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(); + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/HelloProtoWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/HelloProtoWebApp.java index bf748c5..469fba9 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/HelloProtoWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/HelloProtoWebApp.java @@ -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; + } +} diff --git a/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto b/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto index e31485b..c284302 100644 --- a/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto +++ b/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto @@ -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; } \ No newline at end of file diff --git a/bulletin-board-server/src/main/webapp/META-INF/jetty-env.xml b/bulletin-board-server/src/main/webapp/META-INF/jetty-env.xml index c4d368f..07c1470 100644 --- a/bulletin-board-server/src/main/webapp/META-INF/jetty-env.xml +++ b/bulletin-board-server/src/main/webapp/META-INF/jetty-env.xml @@ -1,12 +1,12 @@ - - - - - org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern - none - - - org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern - none - + + + + + org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern + none + + + org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern + none + \ No newline at end of file diff --git a/bulletin-board-server/src/main/webapp/WEB-INF/web.xml b/bulletin-board-server/src/main/webapp/WEB-INF/web.xml index 2198c07..7e91168 100644 --- a/bulletin-board-server/src/main/webapp/WEB-INF/web.xml +++ b/bulletin-board-server/src/main/webapp/WEB-INF/web.xml @@ -1,38 +1,38 @@ - - - Jersey Hello World - - org.glassfish.jersey.servlet.ServletContainer - - - jersey.config.server.provider.packages - meerkat - - 1 - - - Jersey Hello World - /* - - - dbAddress - localhost - - dbPort - 3306 - - dbName - meerkat - - username - arbel - - password - mypass - - dbType - SQLite - - meerkat.bulletinboard.webapp.BulletinBoardWebApp - - + + + Jersey Hello World + + org.glassfish.jersey.servlet.ServletContainer + + + jersey.config.server.provider.packages + meerkat + + 1 + + + Jersey Hello World + /* + + + dbAddress + localhost + + dbPort + 3306 + + dbName + meerkat + + username + arbel + + password + mypass + + dbType + SQLite + + meerkat.bulletinboard.webapp.BulletinBoardWebApp + + diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java index 838adcc..eb3465b 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java @@ -1,124 +1,124 @@ -package meerkat.bulletinboard; - - -import com.google.protobuf.ByteString; -import com.google.protobuf.TextFormat; - -import meerkat.protobuf.Crypto.*; -import meerkat.protobuf.BulletinBoardAPI.*; -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.Response; - -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}; - - WebTarget webTarget; - Response response; - BoolMsg bool; - - BulletinBoardMessage msg; - - MessageFilterList filterList; - BulletinBoardMessageList msgList; - - // Test writing mechanism - - System.err.println("******** Testing: " + Constants.POST_MESSAGE_PATH); - webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH); - System.err.println(webTarget.getUri()); - - 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()) - .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)) - .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: " + Constants.READ_MESSAGES_PATH); - webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH); - filterList = MessageFilterList.newBuilder() - .addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag("Vote") - .build() - ) - .build(); - - response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF)); - System.err.println(response); - msgList = response.readEntity(BulletinBoardMessageList.class); - System.err.println("List size: " + msgList.getMessageCount()); - System.err.println("This is the list:"); - System.err.println(TextFormat.printToString(msgList)); - assert msgList.getMessageCount() == 1; - } - -} +package meerkat.bulletinboard; + + +import com.google.protobuf.ByteString; +import com.google.protobuf.TextFormat; + +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.BulletinBoardAPI.*; +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.Response; + +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}; + + WebTarget webTarget; + Response response; + BoolMsg bool; + + BulletinBoardMessage msg; + + MessageFilterList filterList; + BulletinBoardMessageList msgList; + + // Test writing mechanism + + System.err.println("******** Testing: " + Constants.POST_MESSAGE_PATH); + webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH); + System.err.println(webTarget.getUri()); + + 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()) + .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)) + .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: " + Constants.READ_MESSAGES_PATH); + webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH); + filterList = MessageFilterList.newBuilder() + .addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag("Vote") + .build() + ) + .build(); + + response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF)); + System.err.println(response); + msgList = response.readEntity(BulletinBoardMessageList.class); + System.err.println("List size: " + msgList.getMessageCount()); + System.err.println("This is the list:"); + System.err.println(TextFormat.printToString(msgList)); + assert msgList.getMessageCount() == 1; + } + +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 4799e0d..1c5e3c5 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -1,391 +1,391 @@ -package meerkat.bulletinboard; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.util.List; -import java.util.Random; - -import com.google.protobuf.ByteString; - -import meerkat.comm.CommunicationException; -import meerkat.crypto.concrete.ECDSASignature; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.FilterType; -import meerkat.protobuf.BulletinBoardAPI.MessageFilter; -import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; -import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; - -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; - -public class GenericBulletinBoardServerTest { - - protected BulletinBoardServer bulletinBoardServer; - private ECDSASignature signers[]; - private ByteString[] signerIDs; - - private Random random; - - private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; - private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12"; - - private static String KEYFILE_PASSWORD1 = "secret"; - private static String KEYFILE_PASSWORD3 = "shh"; - - public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; - public static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; - - private final int TAG_NUM = 5; // Number of tags. - private final int MESSAGE_NUM = 32; // Number of messages (2^TAG_NUM). - - private String[] tags; - private byte[][] data; - - private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests - - /** - * @param bulletinBoardServer is an initialized server. - * @throws InstantiationException - * @throws IllegalAccessException - * @throws CertificateException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws IOException - * @throws UnrecoverableKeyException - * @throws CommunicationException - */ - public void init(BulletinBoardServer bulletinBoardServer) { - - System.err.println("Starting to initialize GenericBulletinBoardServerTest"); - long start = threadBean.getCurrentThreadCpuTime(); - - this.bulletinBoardServer = bulletinBoardServer; - - signers = new ECDSASignature[2]; - signerIDs = new ByteString[signers.length]; - signers[0] = new ECDSASignature(); - signers[1] = new ECDSASignature(); - - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD1.toCharArray(); - - KeyStore.Builder keyStoreBuilder = null; - try { - keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); - - signers[0].loadSigningCertificate(keyStoreBuilder); - - signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); - password = KEYFILE_PASSWORD3.toCharArray(); - - keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); - signers[1].loadSigningCertificate(keyStoreBuilder); - - signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); - - for (int i = 0 ; i < signers.length ; i++) { - signerIDs[i] = signers[i].getSignerID(); - } - - } catch (IOException e) { - System.err.println("Failed reading from signature file " + e.getMessage()); - fail("Failed reading from signature file " + e.getMessage()); - } catch (CertificateException e) { - System.err.println("Failed reading certificate " + e.getMessage()); - fail("Failed reading certificate " + e.getMessage()); - } catch (KeyStoreException e) { - System.err.println("Failed reading keystore " + e.getMessage()); - fail("Failed reading keystore " + e.getMessage()); - } catch (NoSuchAlgorithmException e) { - System.err.println("Couldn't find signing algorithm " + e.getMessage()); - fail("Couldn't find signing algorithm " + e.getMessage()); - } catch (UnrecoverableKeyException e) { - System.err.println("Couldn't find signing key " + e.getMessage()); - fail("Couldn't find signing key " + e.getMessage()); - } - - random = new Random(0); // We use insecure randomness in tests for repeatability - - long end = threadBean.getCurrentThreadCpuTime(); - System.err.println("Finished initializing GenericBulletinBoardServerTest"); - System.err.println("Time of operation: " + (end - start)); - } - - private byte randomByte(){ - return (byte) random.nextInt(); - } - - private String randomString(){ - return new BigInteger(130, random).toString(32); - } - - /** - * Tests writing of several messages with multiple tags and signatures. - * @throws CommunicationException - * @throws SignatureException - * @throws InvalidKeyException - * @throws CertificateException - * @throws IOException - */ - public void testInsert() { - - System.err.println("Starting to insert messages to DB"); - long start = threadBean.getCurrentThreadCpuTime(); - - final int BYTES_PER_MESSAGE_DATA = 50; // Message size. - - tags = new String[TAG_NUM]; - data = new byte[MESSAGE_NUM][BYTES_PER_MESSAGE_DATA]; - - UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder; - BulletinBoardMessage.Builder msgBuilder; - - int i, j; - - // Generate random data. - - for (i = 1; i <= MESSAGE_NUM; i++) { - for (j = 0; j < BYTES_PER_MESSAGE_DATA; j++) { - data[i - 1][j] = randomByte(); - } - } - - for (i = 0; i < TAG_NUM; i++) { - tags[i] = randomString(); - } - - // Build messages. - - for (i = 1; i <= MESSAGE_NUM; i++) { - unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder() - .setData(ByteString.copyFrom(data[i - 1])); - - // Add tags based on bit-representation of message number. - - int copyI = i; - for (j = 0; j < TAG_NUM; j++) { - if (copyI % 2 == 1) { - unsignedMsgBuilder.addTag(tags[j]); - } - - copyI >>>= 1; - } - - // Build message. - - msgBuilder = BulletinBoardMessage.newBuilder() - .setMsg(unsignedMsgBuilder.build()); - - // Add signatures. - - try { - - if (i % 2 == 1) { - signers[0].updateContent(msgBuilder.getMsg()); - msgBuilder.addSig(signers[0].sign()); - - if (i % 4 == 1) { - signers[1].updateContent(msgBuilder.getMsg()); - msgBuilder.addSig(signers[1].sign()); - } - } - - } catch (SignatureException e) { - fail(e.getMessage()); - } - - // Post message. - - try { - bulletinBoardServer.postMessage(msgBuilder.build()); - } catch (CommunicationException e) { - fail(e.getMessage()); - } - } - - long end = threadBean.getCurrentThreadCpuTime(); - System.err.println("Finished inserting messages to DB"); - System.err.println("Time of operation: " + (end - start)); - - } - - /** - * Tests retrieval of messages written in {@Link #testInsert()} - * Only queries using one tag filter - */ - public void testSimpleTagAndSignature(){ - - System.err.println("Starting to test tag and signature mechanism"); - long start = threadBean.getCurrentThreadCpuTime(); - - List messages; - - // Check tag mechanism - - for (int i = 0 ; i < TAG_NUM ; i++){ - - // Retrieve messages having tag i - - try { - - messages = bulletinBoardServer.readMessages( - MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(tags[i]) - .build() - ) - .build() - ) - .getMessageList(); - - } catch (CommunicationException e) { - fail(e.getMessage()); - return; - } - - // Assert that the number of retrieved messages is correct. - - assertThat(messages.size(), is(MESSAGE_NUM / 2)); - - // Assert the identity of the messages. - - for (BulletinBoardMessage msg : messages){ - - // Assert serial number and raw data. - - assertThat((msg.getEntryNum() >>> i) % 2 , is((long) 1)); - assertThat(msg.getMsg().getData().toByteArray(), is(data[(int) msg.getEntryNum() - 1])); - - // Assert signatures. - - try { - - if (msg.getEntryNum() % 2 == 1) { - signers[0].initVerify(msg.getSig(0)); - signers[0].updateContent(msg.getMsg()); - assertTrue("Signature did not verify!", signers[0].verify()); - - if (msg.getEntryNum() % 4 == 1) { - signers[1].initVerify(msg.getSig(1)); - signers[1].updateContent(msg.getMsg()); - assertTrue("Signature did not verify!", signers[1].verify()); - - assertThat(msg.getSigCount(), is(2)); - } else { - assertThat(msg.getSigCount(), is(1)); - } - } else { - assertThat(msg.getSigCount(), is(0)); - } - } catch (Exception e) { - fail(e.getMessage()); - } - } - - } - - long end = threadBean.getCurrentThreadCpuTime(); - System.err.println("Finished testing tag and signature mechanism"); - System.err.println("Time of operation: " + (end - start)); - - } - - /** - * Tests retrieval of messages written in {@Link #testInsert()} using multiple tags/signature filters. - */ - public void testEnhancedTagsAndSignatures(){ - - System.err.println("Starting to test multiple tags and signatures"); - long start = threadBean.getCurrentThreadCpuTime(); - - List messages; - MessageFilterList.Builder filterListBuilder = MessageFilterList.newBuilder(); - - int expectedMsgCount = MESSAGE_NUM; - - // Check multiple tag filters. - - for (int i = 0 ; i < TAG_NUM ; i++) { - - filterListBuilder.addFilter( - MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(tags[i]) - .build() - ); - - try { - messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); - } catch (CommunicationException e) { - System.err.println("Failed retrieving multi-tag messages from DB: " + e.getMessage()); - fail("Failed retrieving multi-tag messages from DB: " + e.getMessage()); - return; - } - - expectedMsgCount /= 2; - - assertThat(messages.size(), is(expectedMsgCount)); - - for (BulletinBoardMessage msg : messages) { - for (int j = 0 ; j <= i ; j++) { - assertThat((msg.getEntryNum() >>> j) % 2, is((long) 1)); - } - } - } - - // Check multiple signature filters. - - filterListBuilder = MessageFilterList.newBuilder() - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(signerIDs[0]) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(signerIDs[1]) - .build()); - - try { - messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); - } catch (CommunicationException e) { - System.err.println("Failed retrieving multi-signature message from DB: " + e.getMessage()); - fail("Failed retrieving multi-signature message from DB: " + e.getMessage()); - return; - } - - assertThat(messages.size(), is(MESSAGE_NUM / 4)); - - for (BulletinBoardMessage message : messages) { - assertThat(message.getEntryNum() % 4, is((long) 1)); - } - - long end = threadBean.getCurrentThreadCpuTime(); - System.err.println("Finished testing multiple tags and signatures"); - System.err.println("Time of operation: " + (end - start)); - - } - - public void close(){ - signers[0].clearSigningKey(); - signers[1].clearSigningKey(); - try { - bulletinBoardServer.close(); - } catch (CommunicationException e) { - System.err.println("Error closing server " + e.getMessage()); - fail("Error closing server " + e.getMessage()); - } - } -} +package meerkat.bulletinboard; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.List; +import java.util.Random; + +import com.google.protobuf.ByteString; + +import meerkat.comm.CommunicationException; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; +import meerkat.protobuf.BulletinBoardAPI.FilterType; +import meerkat.protobuf.BulletinBoardAPI.MessageFilter; +import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; +import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +public class GenericBulletinBoardServerTest { + + protected BulletinBoardServer bulletinBoardServer; + private ECDSASignature signers[]; + private ByteString[] signerIDs; + + private Random random; + + private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + private static String KEYFILE_EXAMPLE3 = "/certs/enduser-certs/user3-key-with-password-shh.p12"; + + private static String KEYFILE_PASSWORD1 = "secret"; + private static String KEYFILE_PASSWORD3 = "shh"; + + public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + public static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; + + private final int TAG_NUM = 5; // Number of tags. + private final int MESSAGE_NUM = 32; // Number of messages (2^TAG_NUM). + + private String[] tags; + private byte[][] data; + + private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests + + /** + * @param bulletinBoardServer is an initialized server. + * @throws InstantiationException + * @throws IllegalAccessException + * @throws CertificateException + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + * @throws IOException + * @throws UnrecoverableKeyException + * @throws CommunicationException + */ + public void init(BulletinBoardServer bulletinBoardServer) { + + System.err.println("Starting to initialize GenericBulletinBoardServerTest"); + long start = threadBean.getCurrentThreadCpuTime(); + + this.bulletinBoardServer = bulletinBoardServer; + + signers = new ECDSASignature[2]; + signerIDs = new ByteString[signers.length]; + signers[0] = new ECDSASignature(); + signers[1] = new ECDSASignature(); + + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD1.toCharArray(); + + KeyStore.Builder keyStoreBuilder = null; + try { + keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); + + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); + password = KEYFILE_PASSWORD3.toCharArray(); + + keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); + signers[1].loadSigningCertificate(keyStoreBuilder); + + signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + + for (int i = 0 ; i < signers.length ; i++) { + signerIDs[i] = signers[i].getSignerID(); + } + + } catch (IOException e) { + System.err.println("Failed reading from signature file " + e.getMessage()); + fail("Failed reading from signature file " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("Failed reading certificate " + e.getMessage()); + fail("Failed reading certificate " + e.getMessage()); + } catch (KeyStoreException e) { + System.err.println("Failed reading keystore " + e.getMessage()); + fail("Failed reading keystore " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.err.println("Couldn't find signing algorithm " + e.getMessage()); + fail("Couldn't find signing algorithm " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + System.err.println("Couldn't find signing key " + e.getMessage()); + fail("Couldn't find signing key " + e.getMessage()); + } + + random = new Random(0); // We use insecure randomness in tests for repeatability + + long end = threadBean.getCurrentThreadCpuTime(); + System.err.println("Finished initializing GenericBulletinBoardServerTest"); + System.err.println("Time of operation: " + (end - start)); + } + + private byte randomByte(){ + return (byte) random.nextInt(); + } + + private String randomString(){ + return new BigInteger(130, random).toString(32); + } + + /** + * Tests writing of several messages with multiple tags and signatures. + * @throws CommunicationException + * @throws SignatureException + * @throws InvalidKeyException + * @throws CertificateException + * @throws IOException + */ + public void testInsert() { + + System.err.println("Starting to insert messages to DB"); + long start = threadBean.getCurrentThreadCpuTime(); + + final int BYTES_PER_MESSAGE_DATA = 50; // Message size. + + tags = new String[TAG_NUM]; + data = new byte[MESSAGE_NUM][BYTES_PER_MESSAGE_DATA]; + + UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder; + BulletinBoardMessage.Builder msgBuilder; + + int i, j; + + // Generate random data. + + for (i = 1; i <= MESSAGE_NUM; i++) { + for (j = 0; j < BYTES_PER_MESSAGE_DATA; j++) { + data[i - 1][j] = randomByte(); + } + } + + for (i = 0; i < TAG_NUM; i++) { + tags[i] = randomString(); + } + + // Build messages. + + for (i = 1; i <= MESSAGE_NUM; i++) { + unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder() + .setData(ByteString.copyFrom(data[i - 1])); + + // Add tags based on bit-representation of message number. + + int copyI = i; + for (j = 0; j < TAG_NUM; j++) { + if (copyI % 2 == 1) { + unsignedMsgBuilder.addTag(tags[j]); + } + + copyI >>>= 1; + } + + // Build message. + + msgBuilder = BulletinBoardMessage.newBuilder() + .setMsg(unsignedMsgBuilder.build()); + + // Add signatures. + + try { + + if (i % 2 == 1) { + signers[0].updateContent(msgBuilder.getMsg()); + msgBuilder.addSig(signers[0].sign()); + + if (i % 4 == 1) { + signers[1].updateContent(msgBuilder.getMsg()); + msgBuilder.addSig(signers[1].sign()); + } + } + + } catch (SignatureException e) { + fail(e.getMessage()); + } + + // Post message. + + try { + bulletinBoardServer.postMessage(msgBuilder.build()); + } catch (CommunicationException e) { + fail(e.getMessage()); + } + } + + long end = threadBean.getCurrentThreadCpuTime(); + System.err.println("Finished inserting messages to DB"); + System.err.println("Time of operation: " + (end - start)); + + } + + /** + * Tests retrieval of messages written in {@Link #testInsert()} + * Only queries using one tag filter + */ + public void testSimpleTagAndSignature(){ + + System.err.println("Starting to test tag and signature mechanism"); + long start = threadBean.getCurrentThreadCpuTime(); + + List messages; + + // Check tag mechanism + + for (int i = 0 ; i < TAG_NUM ; i++){ + + // Retrieve messages having tag i + + try { + + messages = bulletinBoardServer.readMessages( + MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(tags[i]) + .build() + ) + .build() + ) + .getMessageList(); + + } catch (CommunicationException e) { + fail(e.getMessage()); + return; + } + + // Assert that the number of retrieved messages is correct. + + assertThat(messages.size(), is(MESSAGE_NUM / 2)); + + // Assert the identity of the messages. + + for (BulletinBoardMessage msg : messages){ + + // Assert serial number and raw data. + + assertThat((msg.getEntryNum() >>> i) % 2 , is((long) 1)); + assertThat(msg.getMsg().getData().toByteArray(), is(data[(int) msg.getEntryNum() - 1])); + + // Assert signatures. + + try { + + if (msg.getEntryNum() % 2 == 1) { + signers[0].initVerify(msg.getSig(0)); + signers[0].updateContent(msg.getMsg()); + assertTrue("Signature did not verify!", signers[0].verify()); + + if (msg.getEntryNum() % 4 == 1) { + signers[1].initVerify(msg.getSig(1)); + signers[1].updateContent(msg.getMsg()); + assertTrue("Signature did not verify!", signers[1].verify()); + + assertThat(msg.getSigCount(), is(2)); + } else { + assertThat(msg.getSigCount(), is(1)); + } + } else { + assertThat(msg.getSigCount(), is(0)); + } + } catch (Exception e) { + fail(e.getMessage()); + } + } + + } + + long end = threadBean.getCurrentThreadCpuTime(); + System.err.println("Finished testing tag and signature mechanism"); + System.err.println("Time of operation: " + (end - start)); + + } + + /** + * Tests retrieval of messages written in {@Link #testInsert()} using multiple tags/signature filters. + */ + public void testEnhancedTagsAndSignatures(){ + + System.err.println("Starting to test multiple tags and signatures"); + long start = threadBean.getCurrentThreadCpuTime(); + + List messages; + MessageFilterList.Builder filterListBuilder = MessageFilterList.newBuilder(); + + int expectedMsgCount = MESSAGE_NUM; + + // Check multiple tag filters. + + for (int i = 0 ; i < TAG_NUM ; i++) { + + filterListBuilder.addFilter( + MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(tags[i]) + .build() + ); + + try { + messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); + } catch (CommunicationException e) { + System.err.println("Failed retrieving multi-tag messages from DB: " + e.getMessage()); + fail("Failed retrieving multi-tag messages from DB: " + e.getMessage()); + return; + } + + expectedMsgCount /= 2; + + assertThat(messages.size(), is(expectedMsgCount)); + + for (BulletinBoardMessage msg : messages) { + for (int j = 0 ; j <= i ; j++) { + assertThat((msg.getEntryNum() >>> j) % 2, is((long) 1)); + } + } + } + + // Check multiple signature filters. + + filterListBuilder = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(signerIDs[0]) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(signerIDs[1]) + .build()); + + try { + messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); + } catch (CommunicationException e) { + System.err.println("Failed retrieving multi-signature message from DB: " + e.getMessage()); + fail("Failed retrieving multi-signature message from DB: " + e.getMessage()); + return; + } + + assertThat(messages.size(), is(MESSAGE_NUM / 4)); + + for (BulletinBoardMessage message : messages) { + assertThat(message.getEntryNum() % 4, is((long) 1)); + } + + long end = threadBean.getCurrentThreadCpuTime(); + System.err.println("Finished testing multiple tags and signatures"); + System.err.println("Time of operation: " + (end - start)); + + } + + public void close(){ + signers[0].clearSigningKey(); + signers[1].clearSigningKey(); + try { + bulletinBoardServer.close(); + } catch (CommunicationException e) { + System.err.println("Error closing server " + e.getMessage()); + fail("Error closing server " + e.getMessage()); + } + } +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java index ef19310..2792b7a 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -1,122 +1,122 @@ -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 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)); - } - - @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 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)); + } + + @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)); + } + +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/HelloProtoIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/HelloProtoIntegrationTest.java index c7b16df..a0c3653 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/HelloProtoIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/HelloProtoIntegrationTest.java @@ -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")); + } +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java index e473931..20e3f58 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -1,126 +1,126 @@ -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.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -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 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)); - } - - @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.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +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 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)); + } + + @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)); + } + +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java index 1d7aae0..cbbd6f9 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java @@ -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)); + } + +} diff --git a/destributed-key-generation/build.gradle b/destributed-key-generation/build.gradle index 60ec7c9..074667f 100644 --- a/destributed-key-generation/build.gradle +++ b/destributed-key-generation/build.gradle @@ -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 + } + } + } +} + + + diff --git a/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java b/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java index bd9920a..979ea60 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java +++ b/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java @@ -1,14 +1,18 @@ -package Arithmetics; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/17/2016. - */ -public interface Arithmetic { - BigInteger add(T a,T b); - BigInteger sub(T a,T b); - BigInteger mul(T a,T b); - BigInteger div(T a,T b); - -} +package Arithmetics; + +/** + * Created by Tzlil on 3/17/2016. + */ +public interface Arithmetic { + /** + * + * @param a + * @param b + * @return + */ + T add(T a, T b); + T sub(T a, T b); + T mul(T a, T b); + T div(T a, T b); + +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Fp.java b/destributed-key-generation/src/main/java/Arithmetics/Fp.java index db2d6da..0525d08 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Fp.java +++ b/destributed-key-generation/src/main/java/Arithmetics/Fp.java @@ -1,38 +1,38 @@ -package Arithmetics; - -import org.factcenter.qilin.primitives.concrete.Zpstar; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/17/2016. - */ -public class Fp implements Arithmetic { - public final BigInteger p; - private final Zpstar zp; - - 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)); - } -} +package Arithmetics; + +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public class Fp implements Arithmetic { + public final BigInteger p; + private final Zpstar zp; + + 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)); + } +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Z.java b/destributed-key-generation/src/main/java/Arithmetics/Z.java index 9523ead..acf486d 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Z.java +++ b/destributed-key-generation/src/main/java/Arithmetics/Z.java @@ -1,29 +1,29 @@ -package Arithmetics; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/17/2016. - */ -public class Z implements Arithmetic { - - @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); - } -} +package Arithmetics; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public class Z implements Arithmetic { + + @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); + } +} diff --git a/destributed-key-generation/src/main/java/Communication/Channel.java b/destributed-key-generation/src/main/java/Communication/Channel.java new file mode 100644 index 0000000..cedb213 --- /dev/null +++ b/destributed-key-generation/src/main/java/Communication/Channel.java @@ -0,0 +1,28 @@ +package Communication; + +/** + * A generic commmunication channel that supports point-to-point and broadcast operation + */ +// +//public interface Channel { +// public interface ReceiverCallback { +// public void receiveMessage(UserID fromUser, boolean isBroadcast, Message message); +// } +// +// public void sendMessage(UserID destUser, Message msg); +// +// /** +// * Block until a message is available (optional). +// * @return +// */ +// public Message getNextMessageBlocking(long timeout); +// +// +// /** +// * Register a callback to handle received messages. +// * The callback is called in the Channel thread, so no long processing should +// * occur in the callback method. +// * @param callback +// */ +// public void registerReceiverCallback(ReceiverCallback callback); +//} diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/Communication/MailHandler.java index fbb0522..23fd840 100644 --- a/destributed-key-generation/src/main/java/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MailHandler.java @@ -1,59 +1,58 @@ -package Communication; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/14/2016. - */ -public abstract class MailHandler { - - private MessageHandler messageHandler; - public MailHandler(MessageHandler messageHandler){ - this.messageHandler = messageHandler; - } - - public abstract Message extractMessage(DKGMessages.Mail mail); - - public void handel(DKGMessages.Mail mail){ - - Message message = extractMessage(mail); - if (message == null) - return; - - switch (mail.getType()) { - case SECRET: - messageHandler.handelSecretMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case COMMITMENT: - messageHandler.handelCommitmentMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case DONE: - messageHandler.handelDoneMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case COMPLAINT: - messageHandler.handelComplaintMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case ANSWER: - messageHandler.handelAnswerMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case ABORT: - messageHandler.handelAbortMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - default: - break; - } - - - } - public void setMessageHandler(MessageHandler messageHandler) { - this.messageHandler = messageHandler; - } -} +package Communication; + +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/14/2016. + */ +public abstract class MailHandler { + + private MessageHandler messageHandler; + public MailHandler(MessageHandler messageHandler){ + this.messageHandler = messageHandler; + } + + public abstract Message extractMessage(DKGMessages.Mail mail); + + public void handel(DKGMessages.Mail mail){ + + Message message = extractMessage(mail); + if (message == null) + return; + + switch (mail.getType()) { + case SECRET: + messageHandler.handleSecretMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + case COMMITMENT: + messageHandler.handleCommitmentMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + case DONE: + messageHandler.handleDoneMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + case COMPLAINT: + messageHandler.handleComplaintMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + case ANSWER: + messageHandler.handleAnswerMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + case ABORT: + messageHandler.handleAbortMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST + , message); + break; + default: + break; + } + + + } + public void setMessageHandler(MessageHandler messageHandler) { + this.messageHandler = messageHandler; + } +} diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/Communication/MessageHandler.java index 8cedf4e..2bbf3c4 100644 --- a/destributed-key-generation/src/main/java/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/Communication/MessageHandler.java @@ -1,15 +1,15 @@ -package Communication; - -import com.google.protobuf.Message; - -/** - * Created by Tzlil on 2/14/2016. - */ -public interface MessageHandler { - void handelSecretMessage(int sender, boolean isBroadcast, Message message); - void handelCommitmentMessage(int sender, boolean isBroadcast, Message message); - void handelComplaintMessage(int sender, boolean isBroadcast, Message message); - void handelDoneMessage(int sender, boolean isBroadcast, Message message); - void handelAnswerMessage(int sender, boolean isBroadcast, Message message); - void handelAbortMessage(int sender, boolean isBroadcast, Message message); -} +package Communication; + +import com.google.protobuf.Message; + +/** + * Created by Tzlil on 2/14/2016. + */ +public interface MessageHandler { + void handleSecretMessage(int sender, boolean isBroadcast, Message message); + void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); + void handleComplaintMessage(int sender, boolean isBroadcast, Message message); + void handleDoneMessage(int sender, boolean isBroadcast, Message message); + void handleAnswerMessage(int sender, boolean isBroadcast, Message message); + void handleAbortMessage(int sender, boolean isBroadcast, Message message); +} diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java index 541179e..8de25b3 100644 --- a/destributed-key-generation/src/main/java/Communication/Network.java +++ b/destributed-key-generation/src/main/java/Communication/Network.java @@ -1,73 +1,75 @@ -package Communication; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages.*; - -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ArrayBlockingQueue; -/** - * Created by Tzlil on 2/7/2016. - * Joint Feldamn protocol assumes all parties can communicate throw broadcast chanel - * and private chanel (for each pair) - * this class simulates it - */ -public class Network { - - protected final User[] users; - protected final int n; - protected final Set availableIDs; - public static final int BROADCAST = 0; - - - public Network(int n) { - this.n = n; - this.users = new User[n]; - this.availableIDs = new HashSet(); - for (int id = 1; id <= n; id++){ - availableIDs.add(id); - } - } - - public User connect(MailHandler mailHandler,int id){ - if (!availableIDs.contains(id)) - return null; - availableIDs.remove(id); - users[id - 1] = new User(id,this,mailHandler); - return users[id - 1]; - } - - protected boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ - if(destination < 1 || destination > n) - return false; - User user = users[destination - 1]; - if (user == null) - return false; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(destination) - .setIsPrivate(true) - .setType(type) - .setMessage(message.toByteString()) - .build(); - return user.mailbox.add(mail); - } - - protected void sendBroadcast(User sender,Mail.Type type,Message message){ - User user; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(BROADCAST) - .setIsPrivate(false) - .setType(type) - .setMessage(message.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - user = users[i]; - user.mailbox.add(mail); - } - } - -} +package Communication; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages.*; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +/** + * Created by Tzlil on 2/7/2016. + * Joint Feldamn protocol assumes all parties can communicate throw broadcast channel + * and private channel (for each pair) + * this class simulates it + */ +// TODO: Delete +// TODO: Move this implementation to tests +public class Network { + + protected final User[] users; + protected final int n; + protected final Set availableIDs; + public static final int BROADCAST = 0; + + + public Network(int n) { + this.n = n; + this.users = new User[n]; + this.availableIDs = new HashSet(); + for (int id = 1; id <= n; id++){ + availableIDs.add(id); + } + } + + public User connect(MailHandler mailHandler,int id){ + if (!availableIDs.contains(id)) + return null; + availableIDs.remove(id); + users[id - 1] = new User(id,this,mailHandler); + return users[id - 1]; + } + + protected boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ + if(destination < 1 || destination > n) + return false; + User user = users[destination - 1]; + if (user == null) + return false; + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(destination) + .setIsPrivate(true) + .setType(type) + .setMessage(message.toByteString()) + .build(); + return user.mailbox.add(mail); + } + + protected void sendBroadcast(User sender,Mail.Type type,Message message){ + User user; + Mail mail = Mail.newBuilder() + .setSender(sender.getID()) + .setDestination(BROADCAST) + .setIsPrivate(false) + .setType(type) + .setMessage(message.toByteString()) + .build(); + for (int i = 0 ; i < n ; i++){ + user = users[i]; + user.mailbox.add(mail); + } + } + +} diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java index 2077d6e..1eb6e4a 100644 --- a/destributed-key-generation/src/main/java/Communication/User.java +++ b/destributed-key-generation/src/main/java/Communication/User.java @@ -1,66 +1,74 @@ -package Communication; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Created by Tzlil on 2/14/2016. - */ -public class User{ - protected final MailHandler mailHandler; - protected final Queue mailbox; - protected final int ID; - protected final Thread receiverThread; - private final Network network; - - protected User(int ID, Network network, MailHandler mailHandler) { - this.mailbox = new ArrayBlockingQueue( network.n * network.n * network.n); - this.ID = ID; - this.mailHandler = mailHandler; - this.receiverThread = new Thread(new Receiver()); - this.network = network; - } - - public boolean send(int id, DKGMessages.Mail.Type type, Message message){ - return network.sendMessage(this,id,type,message); - } - - public void broadcast(DKGMessages.Mail.Type type, Message message){ - network.sendBroadcast(this,type,message); - } - public MailHandler getMailHandler(){ - return mailHandler; - } - public void setMessageHandler(MessageHandler messageHandler) { - mailHandler.setMessageHandler(messageHandler); - } - - public int getID() { - return ID; - } - public Thread getReceiverThread(){ - return receiverThread; - } - private class Receiver implements Runnable{ - @Override - public void run() { - while (true){ - if (!mailbox.isEmpty()){ - mailHandler.handel(mailbox.poll()); - }else{ - try { - Thread.sleep(30); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - } - - -} +package Communication; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +/** + * Created by Tzlil on 2/14/2016. + */ +// TODO: Change nane to network + +public class User{ + /* + * My view of + */ + + + + protected final MailHandler mailHandler; + protected final Queue mailbox; + protected final int ID; + protected final Thread receiverThread; + private final Network network; + + protected User(int ID, Network network, MailHandler mailHandler) { + this.mailbox = new ArrayBlockingQueue( network.n * network.n * network.n); + this.ID = ID; + this.mailHandler = mailHandler; + this.receiverThread = new Thread(new Receiver()); + this.network = network; + } + + public boolean send(int id, DKGMessages.Mail.Type type, Message message){ + return network.sendMessage(this,id,type,message); + } + + public void broadcast(DKGMessages.Mail.Type type, Message message){ + network.sendBroadcast(this,type,message); + } + public MailHandler getMailHandler(){ + return mailHandler; + } + public void setMessageHandler(MessageHandler messageHandler) { + mailHandler.setMessageHandler(messageHandler); + } + + public int getID() { + return ID; + } + public Thread getReceiverThread(){ + return receiverThread; + } + private class Receiver implements Runnable{ + @Override + public void run() { + while (true){ + if (!mailbox.isEmpty()){ + mailHandler.handel(mailbox.poll()); + }else{ + try { + Thread.sleep(30); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + } + + +} diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java index 4573c57..7b5b7ad 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java @@ -1,96 +1,102 @@ -package FeldmanVerifiableSecretSharing; - -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; - -import org.factcenter.qilin.primitives.Group; -import java.util.Arrays; -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 extends SecretSharing { - protected final Group group; - protected final BigInteger g; // public generator of group - protected final BigInteger[] commitmentsArray; - /** - * @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 x, Random random, BigInteger q, BigInteger g - , Group group) { - super(t, n, x, random,q); - this.g = g; - this.group = group; - assert (this.group.contains(g)); - this.commitmentsArray = generateCommitments(); - } - - /** - * @return commitments[i] = g ^ polynomial.coefficients[i] - */ - private BigInteger[] generateCommitments() { - - Polynomial polynomial = getPolynomial(); - BigInteger[] coefficients = polynomial.getCoefficients(); - BigInteger[] commitments = new BigInteger[coefficients.length]; - for (int i = 0 ; i < commitments.length;i++){ - commitments[i] = group.multiply(g,coefficients[i]); - } - return commitments; - } - - /** - * @param j share holder id - * @param commitments - * @param group - * - * @return product of Aik ^ (j ^ k) == g ^ polynomial(i) - */ - public static BigInteger verify(int j,BigInteger[] commitments,Group group) { - BigInteger v = group.zero(); - BigInteger power = BigInteger.ONE; - BigInteger J = BigInteger.valueOf(j); - for (int k = 0 ; k < commitments.length ; k ++){ - v = group.add(v,group.multiply(commitments[k],power)); - power = power.multiply(J); - } - return v; - } - - - /** - * getter - * @return generator of group - */ - public BigInteger getGenerator() { - return g; - } - - /** - * getter - * @return group - */ - public Group getGroup(){ - return group; - } - - /** - * getter - * @return copy of commitmentsArray - */ - public BigInteger[] getCommitmentsArray() { - return Arrays.copyOf(commitmentsArray, commitmentsArray.length); - } - -} +package FeldmanVerifiableSecretSharing; + +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; + +import org.factcenter.qilin.primitives.Group; +import java.util.Arrays; +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. + * + * TODO: Add link to paper + * + */ +// TODO: Use Group rather than fix to biginteger (allow using EC groups for better comm. complexity) +public class VerifiableSecretSharing extends SecretSharing { + protected final Group group; + protected final BigInteger g; // public generator of group + protected final BigInteger[] commitmentsArray; + /** + * @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 x, Random random, BigInteger q, BigInteger g + , Group group) { + super(t, n, x, random,q); + this.g = g; + this.group = group; + assert (this.group.contains(g)); + this.commitmentsArray = generateCommitments(); + } + + /** + * TODO: comment + * @return commitments[i] = g ^ polynomial.coefficients[i] + */ + private BigInteger[] generateCommitments() { + + Polynomial polynomial = getPolynomial(); + BigInteger[] coefficients = polynomial.getCoefficients(); + BigInteger[] commitments = new BigInteger[coefficients.length]; + for (int i = 0 ; i < commitments.length;i++){ + commitments[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 BigInteger computeVerificationValue(int j, BigInteger[] commitments, Group group) { + BigInteger v = group.zero(); + BigInteger power = BigInteger.ONE; + BigInteger J = BigInteger.valueOf(j); + for (int k = 0 ; k < commitments.length ; k ++){ + v = group.add(v,group.multiply(commitments[k],power)); + power = power.multiply(J); + } + return v; + } + + // TODO: Add verify method. + + /** + * getter + * @return generator of group + */ + public BigInteger getGenerator() { + return g; + } + + /** + * getter + * @return group + */ + public Group getGroup(){ + return group; + } + + /** + * getter + * @return copy of commitmentsArray + */ + public BigInteger[] getCommitmentsArray() { + return Arrays.copyOf(commitmentsArray, commitmentsArray.length); + } + +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java index d9ae852..a60fd33 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java @@ -1,233 +1,280 @@ -package JointFeldmanProtocol; - -import Communication.User; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import ShamirSecretSharing.Polynomial; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class DistributedKeyGeneration extends VerifiableSecretSharing { - public enum ComplaintState { - Non, Waiting,Disqualified,NonDisqualified - } - protected final int id; - private DistributedKeyGenerationParty[] parties; - - - public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g - , Group group, int id) { - super(t, n, zi, random, q, g,group); - this.id = id; - this.parties = new DistributedKeyGenerationParty[n]; - for (int i = 1; i <= n ; i++){ - this.parties[i - 1] = new DistributedKeyGenerationParty(i,n,t); - } - this.parties[id - 1].share = getShare(id); - } - - protected void setParties(DistributedKeyGenerationParty[] parties){ - this.parties = parties; - } - protected DistributedKeyGenerationParty[] getParties(){ - return parties; - } - - /** - * stage1.1 according to the protocol - * Pi broadcasts Aik for k = 0,...,t. - */ - public void broadcastCommitments(User user){ - broadcastCommitments(user,commitmentsArray); - } - - public void broadcastCommitments(User user, BigInteger[] commitments){ - DKGMessages.CommitmentMessage commitmentMessage; - for (int k = 0; k <= t ; k++){ - commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() - .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) - .setK(k) - .build(); - user.broadcast(DKGMessages.Mail.Type.COMMITMENT, commitmentMessage); - } - } - - public void sendSecret(User user, int j){ - ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); - user.send(j, DKGMessages.Mail.Type.SECRET, - DKGMessages.SecretMessage.newBuilder() - .setI(id) - .setJ(j) - .setSecret(secret) - .build()); - } - - /** - * stage1.2 according to the protocol - * Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj. - */ - public void sendSecrets(User user){ - for (int j = 1; j <= n ; j++){ - if(j != id){ - sendSecret(user,j); - } - } - } - - public boolean isValidSecret(int i){ - DistributedKeyGenerationParty party = parties[i - 1]; - return isValidSecret(party.share,party.commitments,id); - } - - /** - * - * @param secret - * @param commitments - * @param j - * @return verify(j,commitments,group) == g ^ secret.y mod q - */ - public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ - try{ - BigInteger v = verify(j,commitments,group); - return group.multiply(g,secret.y).equals(v); - } - catch (NullPointerException e){ - return false; - } - } - - /** - * stage2 according to the protocol - * Pj verifies all the shares he received (using isValidSecret) - * if check fails for an index i, Pj broadcasts a complaint against Pi. - */ - public void broadcastComplaints(User user){ - for (int i = 1; i <= n ; i++ ){ - if(i != id && !isValidSecret(i)) { - broadcastComplaint(user,i); - } - } - } - - private void broadcastComplaint(User user, int i){ - //message = new Message(Type.Complaint, j) - DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); - } - - public void broadcastComplaintAnswer(User user, int j){ - user.broadcast(DKGMessages.Mail.Type.ANSWER, DKGMessages.SecretMessage.newBuilder() - .setI(id) - .setJ(j) - .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) - .build()); - } - - /** - * stage3.1 according to the protocol - * if more than t players complain against a player Pi he is disqualified. - */ - public void answerAllComplainingPlayers(User user){ - ComplaintState[] complaints = parties[id - 1].complaints; - for (int i = 1; i <= n ; i++) { - switch (complaints[i - 1]) { - case Waiting: - broadcastComplaintAnswer(user,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 calcQUAL(){ - Set QUAL = new HashSet(); - boolean nonDisqualified; - int counter; - for (int i = 1; i <= n; i++){ - ComplaintState[] complaints = parties[i - 1].complaints; - nonDisqualified = true; - counter = 0; - for (int j = 1; j <= n; j++){ - switch (complaints[j - 1]) { - case Non: - break; - case NonDisqualified: - counter++; - default: - nonDisqualified = false; - } - if(!nonDisqualified) - break; - } - if(nonDisqualified && counter <= t){ - QUAL.add(i); - } - } - return QUAL; - } - - /** - * stage4.1 according to the protocol - * public value y is computed as y = multiplication of yi mod p for i in QUAL - */ - public BigInteger calcY(Set QUAL){ - BigInteger y = group.zero(); - for (int i : QUAL) { - y = group.add(y , parties[i - 1].commitments[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 BigInteger[] calcCommitments(Set QUAL){ - BigInteger[] commitments = new BigInteger[t + 1]; - Arrays.fill(commitments,group.zero()); - for (int i : QUAL) { - for (int k = 0; k <= t; k++){ - commitments[k] = group.add(commitments[k], parties[i - 1].commitments[k]); - } - } - return commitments; - } - - /** - * stage4.3 according to the protocol - * Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL - */ - public Polynomial.Point calcShare(Set QUAL){ - BigInteger xj = BigInteger.ZERO; - for (int i : QUAL) { - xj = xj.add(parties[i - 1].share.y); - } - return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); - } - - /** - * getter - * @return id - */ - public int getId() { - return id; - } - -} +package JointFeldmanProtocol; + +import Communication.User; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import ShamirSecretSharing.Polynomial; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 3/14/2016. + */ +// TODO: Lots of comments... +// TODO: User Channel instead of User +public class DistributedKeyGeneration extends VerifiableSecretSharing { + 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 DistributedKeyGenerationParty[] parties; + + + // TODO: Copy comment + public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g + , Group group, int id) { + super(t, n, zi, random, q, g,group); + this.id = id; + this.parties = new DistributedKeyGenerationParty[n]; + for (int i = 1; i <= n ; i++){ + this.parties[i - 1] = new DistributedKeyGenerationParty(i,n,t); + } + this.parties[id - 1].share = getShare(id); + } + + protected void setParties(DistributedKeyGenerationParty[] parties){ + this.parties = parties; + } + + protected DistributedKeyGenerationParty[] getParties(){ + return parties; + } + + /** + * stage1.1 according to the protocol + * Pi broadcasts Aik for k = 0,...,t. + */ + public void broadcastCommitments(User user){ + broadcastCommitments(user,commitmentsArray); + } + + public void broadcastCommitments(User user, BigInteger[] commitments){ + DKGMessages.CommitmentMessage commitmentMessage; + for (int k = 0; k <= t ; k++){ + commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() + .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) + .setK(k) + .build(); + user.broadcast(DKGMessages.Mail.Type.COMMITMENT, commitmentMessage); + } + } + + /** + * Send user j her secret share (of my polynomial) + * @param user + * @param j + */ + public void sendSecret(User user, int j){ + ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); + user.send(j, DKGMessages.Mail.Type.SECRET, + DKGMessages.SecretMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(secret) + .build()); + } + + /** + * stage1.2 according to the protocol + * Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj. + */ + public void sendSecrets(User user){ + for (int j = 1; j <= n ; j++){ + if(j != id){ + sendSecret(user,j); + } + } + } + + /** + * TODO: comment + * @param i + * @return + */ + public boolean isValidSecret(int i){ + DistributedKeyGenerationParty party = parties[i - 1]; + return isValidSecret(party.share,party.commitments,id); + } + + /** + * TODO: Move to VerifiableSecretSharing + * @param secret + * @param commitments + * @param j + * @return computeVerificationValue(j,commitments,group) == g ^ secret.y mod q + */ + public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ + try{ + BigInteger v = computeVerificationValue(j,commitments,group); + return group.multiply(g,secret.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(User user){ + for (int i = 1; i <= n ; i++ ){ + if(i != id && !isValidSecret(i)) { + broadcastComplaint(user,i); + } + } + } + + private void broadcastComplaint(User user, int i){ + //message = new Message(Type.Complaint, j) + DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() + .setId(i) + .build(); + user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); + } + + public void broadcastComplaintAnswer(User user, int j){ + user.broadcast(DKGMessages.Mail.Type.ANSWER, DKGMessages.SecretMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) + .build()); + } + + /** + * stage3.1 according to the protocol + * if more than t players complain against a player Pi he is disqualified. + */ + public void answerAllComplainingPlayers(User user){ + ComplaintState[] complaints = parties[id - 1].complaints; + for (int i = 1; i <= n ; i++) { + switch (complaints[i - 1]) { + case Waiting: + broadcastComplaintAnswer(user,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 calcQUAL(){ + Set QUAL = new HashSet(); + boolean nonDisqualified; + int counter; + for (int i = 1; i <= n; i++){ + 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: + // TODO: Add test for false complaint + 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 BigInteger calcY(Set QUAL){ + BigInteger y = group.zero(); + for (int i : QUAL) { + y = group.add(y , parties[i - 1].commitments[0]); + } + return y; + } + + /** + * TODO: better comment. + * 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 BigInteger[] calcCommitments(Set QUAL){ + BigInteger[] commitments = new BigInteger[t + 1]; + Arrays.fill(commitments,group.zero()); + for (int i : QUAL) { + for (int k = 0; k <= t; k++){ + commitments[k] = group.add(commitments[k], parties[i - 1].commitments[k]); + } + } + return commitments; + } + + /** + * TODO: better comment. + * stage4.3 according to the protocol + * Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL + */ + public Polynomial.Point calcShare(Set QUAL){ + BigInteger xj = BigInteger.ZERO; + for (int i : QUAL) { + xj = xj.add(parties[i - 1].share.y); + } + return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); + } + + /** + * getter + * @return id + */ + public int getId() { + return id; + } + +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java index fe141f2..f33959f 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java @@ -1,49 +1,49 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.MessageHandler; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/29/2016. - */ -public class DistributedKeyGenerationMailHandler extends MailHandler { - - public DistributedKeyGenerationMailHandler(MessageHandler messageHandler) { - super(messageHandler); - } - - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SECRET: - message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } -} +package JointFeldmanProtocol; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class DistributedKeyGenerationMailHandler extends MailHandler { + + public DistributedKeyGenerationMailHandler(MessageHandler messageHandler) { + super(messageHandler); + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SECRET: + message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); + break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java index 878ab66..59ef1ea 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java @@ -1,31 +1,32 @@ -package JointFeldmanProtocol; - -import ShamirSecretSharing.Polynomial; - -import java.math.BigInteger; -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 DistributedKeyGenerationParty { - public final int id; - public Polynomial.Point share; - public BigInteger[] commitments; - public boolean doneFlag; - public DistributedKeyGeneration.ComplaintState[] complaints; - public boolean aborted; - - public DistributedKeyGenerationParty(int id, int n, int t) { - this.id = id; - this.share = null; - this.doneFlag = false; - this.complaints = new DistributedKeyGeneration.ComplaintState[n]; - Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.Non); - this.commitments = new BigInteger[t + 1]; - this.aborted = false; - } -} +package JointFeldmanProtocol; + +import ShamirSecretSharing.Polynomial; + +import java.math.BigInteger; +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 + */ +// TODO: comments for every field. +public class DistributedKeyGenerationParty { + public final int id; + public Polynomial.Point share; + public BigInteger[] commitments; + public boolean doneFlag; + public DistributedKeyGeneration.ComplaintState[] complaints; + public boolean aborted; + + public DistributedKeyGenerationParty(int id, int n, int t) { + this.id = id; + this.share = null; + this.doneFlag = false; + this.complaints = new DistributedKeyGeneration.ComplaintState[n]; + Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.OK); + this.commitments = new BigInteger[t + 1]; + this.aborted = false; + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java index 6287526..6198f97 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java @@ -1,382 +1,393 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.Network; -import Communication.User; -import ShamirSecretSharing.Polynomial; -import UserInterface.DistributedKeyGenerationUser; -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Set; -import JointFeldmanProtocol.DistributedKeyGeneration.ComplaintState; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { - - protected final static int SleepTime = 300; - - protected final DistributedKeyGeneration dkg; - - protected final BigInteger g; - protected final Group group; - protected final int n; - protected final int t; - protected final int id; - - protected MessageHandler messageHandler; - protected final User user; - protected final DistributedKeyGenerationParty[] parties; - protected Set QUAL; // set of all non-disqualified parties - protected BigInteger[] commitments; // public verification values - protected Polynomial.Point share; // final share of the secrete - protected BigInteger y; // final public value - - public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network){ - this(dkg,network,new DistributedKeyGenerationMailHandler(null)); - } - public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network, MailHandler mailHandler) { - this.dkg = dkg; - - this.g = dkg.getGenerator(); - this.group = dkg.getGroup(); - this.n = dkg.getN(); - this.t = dkg.getT(); - this.id = dkg.getId(); - - this.messageHandler = new MessageHandler(); - mailHandler.setMessageHandler(this.messageHandler); - this.user = network.connect(mailHandler,dkg.getId()); - this.parties = dkg.getParties(); - this.QUAL = null; - this.commitments = null; - this.share = null; - this.y = null; - } - - /** - * 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(user); - dkg.sendSecrets(user); - } - - protected void waitUntilStageOneCompleted(){ - // all parties send their share or aborted - for (int i = 0 ; i < n ; i++){ - while (parties[i].share == null && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - // all parties broadcast their commitments or aborted - for (int i = 0 ; i < n ; i++){ - for (int k = 0 ; k <= t ; k++) { - while (parties[i].commitments[k] == null && !parties[i].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - } - - /** - * 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(user); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - } - - - protected void waitUntilStageTwoCompleted(){ - // all parties done or aborted - for (int i = 0 ; i < n ; i++){ - while (!parties[i].doneFlag && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - /** - * 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(user); - // wait until there is no complaint waiting for answer - for (int i = 0; i < n; i++){ - for (int j = 0; j < n; j++){ - while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - 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); - } - - protected void startReceiver(){ - user.getReceiverThread().start(); - } - protected void stopReceiver(){ - user.getReceiverThread().interrupt(); - } - - @Override - public void run() { - startReceiver(); - stage1(); - waitUntilStageOneCompleted(); - stage2(); - waitUntilStageTwoCompleted(); - stage3(); - stage4(); - stopReceiver(); - } - - @Override - public BigInteger[] getCommitments() { - return Arrays.copyOf(commitments, commitments.length); - } - - @Override - public BigInteger getGenerator() { - return g; - } - - @Override - public Group getGroup() { - return group; - } - - @Override - public Polynomial.Point getShare() { - return share; - } - - @Override - public int getID() { - return id; - } - - @Override - public int getN() { - return n; - } - - @Override - public int getT() { - return t; - } - - @Override - public BigInteger getPublicValue() { - return y; - } - - @Override - public Set getQUAL() { - return QUAL; - } - - - protected class MessageHandler implements Communication.MessageHandler{ - - /** - * 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, DKGMessages.CommitmentMessage commitmentMessage){ - int i = sender - 1; - int k = commitmentMessage.getK(); - return isBroadcast && parties[i].commitments[k] == null; - } - - /** - * saves the commitment - */ - @Override - public void handelCommitmentMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; - if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ - int i = sender - 1; - int k = commitmentMessage.getK(); - parties[i].commitments[k] = extractCommitment(commitmentMessage); - } - } - - /** - * 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, DKGMessages.SecretMessage secretMessage){ - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - if(sender != i || isBroadcast) - return false; - else - return parties[i - 1].share == null && j == id; - - } - - /** - * saves the secret - */ - @Override - public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; - if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - Polynomial.Point secret = extractSecret(id,secretMessage.getSecret()); - parties[i - 1].share = secret; - } - } - - /** - * 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; - } - - /** - * marks that the sender was finished sending all his complaints - */ - @Override - public void handelDoneMessage(int sender, boolean isBroadcast,Message message) { - if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].doneFlag = true; - } - } - - /** - * 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, DKGMessages.IDMessage complaintMessage){ - int i = sender; - int j = complaintMessage.getId(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.Non); - } - - /** - * marks that the sender was complained against id - */ - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; - } - } - - /** - * 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, DKGMessages.SecretMessage 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(ComplaintState.Waiting); - } - - /** - * 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 - */ - @Override - public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; - if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - Polynomial.Point secret = extractSecret(j,secretMessage.getSecret()); - if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) { - parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; - } else { - parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; - } - if(j == id){ - parties[i - 1].share = secret; - } - } - } - - /** - * marks that the sender was aborted - */ - @Override - public void handelAbortMessage(int sender, boolean isBroadcast, Message message) { - parties[sender - 1].aborted = true; - } - - public Polynomial.Point extractSecret(int i, ByteString secret){ - BigInteger x = BigInteger.valueOf(i); - BigInteger y = new BigInteger(secret.toByteArray()); - return new Polynomial.Point(x,y); - } - - public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ - return new BigInteger(commitmentMessage.getCommitment().toByteArray()); - } - } -} +package JointFeldmanProtocol; + +import Communication.MailHandler; +import Communication.Network; +import Communication.User; +import ShamirSecretSharing.Polynomial; +import UserInterface.DistributedKeyGenerationUser; +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Set; +import JointFeldmanProtocol.DistributedKeyGeneration.ComplaintState; + +/** + * Created by Tzlil on 3/14/2016. + * TODO: Comments + * TODO: Replace polling with monitors/wait/notify (remember synchronization) + */ +public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { + + // TODO: remove + protected final static int SleepTime = 300; + + protected final DistributedKeyGeneration dkg; + + protected final BigInteger g; + protected final Group group; + protected final int n; + protected final int t; + protected final int id; + + protected MessageHandler messageHandler; + protected final User user; + protected final DistributedKeyGenerationParty[] parties; + protected Set QUAL; // set of all non-disqualified parties + protected BigInteger[] commitments; // public verification values + protected Polynomial.Point share; // final share of the secrete + protected BigInteger y; // final public value + + public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network){ + this(dkg,network,new DistributedKeyGenerationMailHandler(null)); + } + public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network, MailHandler mailHandler) { + this.dkg = dkg; + + this.g = dkg.getGenerator(); + this.group = dkg.getGroup(); + this.n = dkg.getN(); + this.t = dkg.getT(); + this.id = dkg.getId(); + + this.messageHandler = new MessageHandler(); + mailHandler.setMessageHandler(this.messageHandler); + this.user = network.connect(mailHandler,dkg.getId()); + this.parties = dkg.getParties(); + this.QUAL = null; + this.commitments = null; + this.share = null; + this.y = null; + } + + /** + * 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(user); + dkg.sendSecrets(user); + } + + + protected void waitUntilStageOneCompleted(){ + // all parties send their share or aborted + for (int i = 0 ; i < n ; i++){ + while (parties[i].share == null && !parties[i].aborted){ + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + // all parties broadcast their commitments or aborted + for (int i = 0 ; i < n ; i++){ + for (int k = 0 ; k <= t ; k++) { + while (parties[i].commitments[k] == null && !parties[i].aborted) { + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + } + + /** + * 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(user); + //broadcast done message after all complaints + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + } + + + protected void waitUntilStageTwoCompleted(){ + // all parties done or aborted + for (int i = 0 ; i < n ; i++){ + while (!parties[i].doneFlag && !parties[i].aborted){ + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + /** + * 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(user); + // wait until there is no complaint waiting for answer + for (int i = 0; i < n; i++){ + for (int j = 0; j < n; j++){ + while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted){ + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + 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); + } + + protected void startReceiver(){ + user.getReceiverThread().start(); + } + protected void stopReceiver(){ + user.getReceiverThread().interrupt(); + } + + @Override + public void run() { + startReceiver(); + stage1(); + waitUntilStageOneCompleted(); + stage2(); + waitUntilStageTwoCompleted(); + stage3(); + stage4(); + stopReceiver(); + } + + /** + * Request the current run loop to exit gracefully + */ + public void stop() { + // TODO: implement + } + + @Override + public BigInteger[] getCommitments() { + return Arrays.copyOf(commitments, commitments.length); + } + + @Override + public BigInteger getGenerator() { + return g; + } + + @Override + public Group getGroup() { + return group; + } + + @Override + public Polynomial.Point getShare() { + return share; + } + + @Override + public int getID() { + return id; + } + + @Override + public int getN() { + return n; + } + + @Override + public int getT() { + return t; + } + + @Override + public BigInteger getPublicValue() { + return y; + } + + @Override + public Set getQUAL() { + return QUAL; + } + + + protected class MessageHandler implements Communication.MessageHandler{ + + /** + * 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, DKGMessages.CommitmentMessage commitmentMessage){ + int i = sender - 1; + int k = commitmentMessage.getK(); + return isBroadcast && parties[i].commitments[k] == null; + } + + /** + * saves the commitment + */ + @Override + public void handleCommitmentMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; + if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ + int i = sender - 1; + int k = commitmentMessage.getK(); + parties[i].commitments[k] = extractCommitment(commitmentMessage); + } + } + + /** + * 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, DKGMessages.SecretMessage secretMessage){ + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + if(sender != i || isBroadcast) + return false; + else + return parties[i - 1].share == null && j == id; + + } + + /** + * saves the secret + */ + @Override + public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; + if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + Polynomial.Point secret = extractSecret(id,secretMessage.getSecret()); + parties[i - 1].share = secret; + } + } + + /** + * 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; + } + + /** + * marks that the sender was finished sending all his complaints + */ + @Override + public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { + if(isValidDoneMessage(sender,isBroadcast)) { + parties[sender - 1].doneFlag = true; + } + } + + /** + * 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, DKGMessages.IDMessage complaintMessage){ + int i = sender; + int j = complaintMessage.getId(); + return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.OK); + } + + /** + * marks that the sender was complained against id + */ + @Override + public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; + } + } + + /** + * 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, DKGMessages.SecretMessage 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(ComplaintState.Waiting); + } + + /** + * 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 + */ + @Override + public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; + if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + Polynomial.Point secret = extractSecret(j,secretMessage.getSecret()); + if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) { + parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; + } else { + parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; + } + if(j == id){ + parties[i - 1].share = secret; + } + } + } + + /** + * marks that the sender was aborted + */ + @Override + public void handleAbortMessage(int sender, boolean isBroadcast, Message message) { + parties[sender - 1].aborted = true; + } + + public Polynomial.Point extractSecret(int i, ByteString secret){ + BigInteger x = BigInteger.valueOf(i); + BigInteger y = new BigInteger(secret.toByteArray()); + return new Polynomial.Point(x,y); + } + + public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ + return new BigInteger(commitmentMessage.getCommitment().toByteArray()); + } + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java index 92c29f3..9aefeb5 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java @@ -1,137 +1,141 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.User; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import JointFeldmanProtocol.DistributedKeyGeneration; -import ShamirSecretSharing.Polynomial; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/16/2016. - */ -public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { - - private VerifiableSecretSharing verifiableSecretSharing; - private final BigInteger h; - private SecureDistributedKeyGenerationParty[] parties; - - public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g - , BigInteger h, Group group, int id) { - super(t, n, zi, random, q, g, group, id); - this.h = h; - BigInteger r = new BigInteger(q.bitLength(),random).mod(q); - this.verifiableSecretSharing = new VerifiableSecretSharing(t,n,r,random,q,h,group); - this.parties = new SecureDistributedKeyGenerationParty[n]; - for (int i = 1; i <= n ; i++){ - this.parties[i - 1] = new SecureDistributedKeyGenerationParty(i,n,t); - } - this.parties[id - 1].share = getShare(id); - this.parties[id - 1].shareT = verifiableSecretSharing.getShare(id); - super.setParties(parties); - } - - protected SecureDistributedKeyGenerationParty[] getParties(){ - return parties; - } - - protected void setParties(SecureDistributedKeyGenerationParty[] parties) { - super.setParties(parties); - this.parties = parties; - } - - - @Override - public void sendSecret(User user, int j) { - Polynomial.Point secret = getShare(j); - Polynomial.Point secretT = verifiableSecretSharing.getShare(j); - DKGMessages.DoubleSecretMessage doubleSecretMessage = doubleSecretMessage(id,j,secret,secretT); - user.send(j, DKGMessages.Mail.Type.SECRET, doubleSecretMessage); - } - - - @Override - public boolean isValidSecret(int i){ - SecureDistributedKeyGenerationParty party = parties[i - 1]; - return isValidSecret(party.share, party.shareT, party.verifiableValues, id); - } - - /** - * @param secret - * @param secretT - * @param verificationValues - * @param j - * @return verify(j,verificationValues,group) == (g ^ secret.y) * (h ^ secretT.y) mod q - */ - public boolean isValidSecret(Polynomial.Point secret,Polynomial.Point secretT, BigInteger[] verificationValues, int j){ - try { - BigInteger v = verify(j, verificationValues, group); - BigInteger exp = group.add(group.multiply(g, secret.y), group.multiply(h, secretT.y)); - return exp.equals(v); - } - catch (NullPointerException e){ - return false; - } - } - - private void broadcastComplaint(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ - DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); - user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); - } - - /** - * stage4.3 according to the protocol - * if check fails for index i, Pj - */ - public void broadcastComplaints(User user, Set QUAL){ - SecureDistributedKeyGenerationParty party; - for (int i : QUAL) { - party = parties[i - 1]; - if (i != id) { - if (!super.isValidSecret(party.share, party.commitments, id)) { - broadcastComplaint(user, party.share, party.shareT, i); - } - } - } - } - - public void broadcastVerificationValues(User user){ - BigInteger[] verificationValues = new BigInteger[t + 1]; - BigInteger[] hBaseCommitments = verifiableSecretSharing.getCommitmentsArray(); - for (int k = 0 ; k < verificationValues.length ; k++){ - verificationValues[k] = group.add(commitmentsArray[k],hBaseCommitments[k]); - } - broadcastCommitments(user,verificationValues); - } - - private DKGMessages.DoubleSecretMessage doubleSecretMessage(int i,int j,Polynomial.Point secret, Polynomial.Point secretT){ - DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() - .setI(i) - .setJ(j) - .setSecret(ByteString.copyFrom(secret.y.toByteArray())) - .setSecretT(ByteString.copyFrom(secretT.y.toByteArray())) - .build(); - return doubleSecretMessage; - } - - @Override - public void broadcastComplaintAnswer(User user, int j) { - DKGMessages.DoubleSecretMessage answer = doubleSecretMessage(id,j,getShare(j) - ,verifiableSecretSharing.getShare(j)); - user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); - } - - public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ - DKGMessages.DoubleSecretMessage complaint = doubleSecretMessage(i,id,secret,secretT); - user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); - } - - public BigInteger getH() { - return h; - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.User; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import JointFeldmanProtocol.DistributedKeyGeneration; +import ShamirSecretSharing.Polynomial; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 3/16/2016. + * TODO: comments + * TODO: put Channel (User) in constructor + */ +public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { + + private VerifiableSecretSharing maskingShares; + private final BigInteger h; + private SecureDistributedKeyGenerationParty[] parties; + + public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g + , BigInteger h, Group group, int id) { + super(t, n, zi, random, q, g, group, id); + 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 SecureDistributedKeyGenerationParty[n]; + for (int i = 1; i <= n ; i++){ + this.parties[i - 1] = new SecureDistributedKeyGenerationParty(i,n,t); + } + this.parties[id - 1].share = getShare(id); + this.parties[id - 1].shareT = maskingShares.getShare(id); + super.setParties(parties); + } + + protected SecureDistributedKeyGenerationParty[] getParties(){ + return parties; + } + + protected void setParties(SecureDistributedKeyGenerationParty[] parties) { + super.setParties(parties); + this.parties = parties; + } + + + @Override + public void sendSecret(User user, int j) { + Polynomial.Point secret = getShare(j); + Polynomial.Point secretT = maskingShares.getShare(j); + DKGMessages.DoubleSecretMessage doubleSecretMessage = doubleShareMessage(id,j,secret,secretT); + // TODO: Change SECRET to SHARE + user.send(j, DKGMessages.Mail.Type.SECRET, doubleSecretMessage); + } + + + public boolean isValidShare(int i){ + SecureDistributedKeyGenerationParty party = parties[i - 1]; + return isValidShare(party.share, party.shareT, party.verifiableValues, id); + } + + /** + * TODO: comment + * @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, BigInteger[] verificationValues, int j){ + try { + BigInteger v = computeVerificationValue(j, verificationValues, group); + BigInteger exp = group.add(group.multiply(g, share.y), group.multiply(h, shareT.y)); + return exp.equals(v); + } + catch (NullPointerException e){ + return false; + } + } + + // TODO: comment + private void broadcastComplaint(User user,Polynomial.Point share,Polynomial.Point shareT,int i){ + DKGMessages.DoubleSecretMessage complaint = doubleShareMessage(i,id,share,shareT); + user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); + } + + /** + * stage4.3 according to the protocol + * if check fails for index i, Pj + */ + public void computeAndBroadcastComplaints(User user, Set QUAL){ + SecureDistributedKeyGenerationParty party; + for (int i : QUAL) { + party = parties[i - 1]; + if (i != id) { + if (!super.isValidSecret(party.share, party.commitments, id)) { + broadcastComplaint(user, party.share, party.shareT, i); + } + } + } + } + + public void broadcastVerificationValues(User user){ + BigInteger[] verificationValues = new BigInteger[t + 1]; + BigInteger[] hBaseCommitments = maskingShares.getCommitmentsArray(); + for (int k = 0 ; k < verificationValues.length ; k++){ + verificationValues[k] = group.add(commitmentsArray[k],hBaseCommitments[k]); + } + broadcastCommitments(user,verificationValues); + } + + private DKGMessages.DoubleSecretMessage doubleShareMessage(int i, int j, Polynomial.Point secret, Polynomial.Point secretT){ + DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() + .setI(i) + .setJ(j) + .setSecret(ByteString.copyFrom(secret.y.toByteArray())) + .setSecretT(ByteString.copyFrom(secretT.y.toByteArray())) + .build(); + return doubleSecretMessage; + } + + @Override + public void broadcastComplaintAnswer(User user, int j) { + DKGMessages.DoubleSecretMessage answer = doubleShareMessage(id,j,getShare(j) + , maskingShares.getShare(j)); + user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); + } + + public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ + DKGMessages.DoubleSecretMessage complaint = doubleShareMessage(i,id,secret,secretT); + user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); + } + + public BigInteger getH() { + return h; + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java index 9b4752e..92dba85 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java @@ -1,63 +1,63 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.MailHandler; -import Communication.MessageHandler; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/29/2016. - */ -public class SecureDistributedKeyGenerationMailHandler extends MailHandler { - - private boolean isStage4; - - public SecureDistributedKeyGenerationMailHandler(MessageHandler messageHandler) { - super(messageHandler); - this.isStage4 = false; - } - - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SECRET: - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - if(!isStage4) - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - else - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } - - public boolean isStage4() { - return isStage4; - } - - public void setStage4(boolean stage4) { - isStage4 = stage4; - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class SecureDistributedKeyGenerationMailHandler extends MailHandler { + + private boolean isStage4; + + public SecureDistributedKeyGenerationMailHandler(MessageHandler messageHandler) { + super(messageHandler); + this.isStage4 = false; + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SECRET: + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + if(!isStage4) + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); + else + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); + break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } + + public boolean isStage4() { + return isStage4; + } + + public void setStage4(boolean stage4) { + isStage4 = stage4; + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java index ea36136..fc2e8e3 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java @@ -1,29 +1,29 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import JointFeldmanProtocol.DistributedKeyGenerationParty; -import ShamirSecretSharing.Polynomial; - -import java.math.BigInteger; -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 SecureDistributedKeyGenerationParty extends DistributedKeyGenerationParty { - public Polynomial.Point shareT; - public boolean ysDoneFlag; - public BigInteger[] verifiableValues; - public Set restoreSharesSet; - public SecureDistributedKeyGenerationParty(int id, int n, int t) { - super(id, n, t); - this.shareT = null; - this.ysDoneFlag = false; - this.verifiableValues = new BigInteger[t + 1]; - this.restoreSharesSet = new HashSet(); - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import JointFeldmanProtocol.DistributedKeyGenerationParty; +import ShamirSecretSharing.Polynomial; + +import java.math.BigInteger; +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 SecureDistributedKeyGenerationParty extends DistributedKeyGenerationParty { + public Polynomial.Point shareT; + public boolean ysDoneFlag; + public BigInteger[] verifiableValues; + public Set restoreSharesSet; + public SecureDistributedKeyGenerationParty(int id, int n, int t) { + super(id, n, t); + this.shareT = null; + this.ysDoneFlag = false; + this.verifiableValues = new BigInteger[t + 1]; + this.restoreSharesSet = new HashSet(); + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java index 66751eb..141b854 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java @@ -1,304 +1,307 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import JointFeldmanProtocol.DistributedKeyGeneration; -import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/16/2016. - */ -public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { - - protected SecureDistributedKeyGenerationParty[] parties; - protected final SecureDistributedKeyGeneration sdkg; - private Arithmetic arithmetic; - private boolean isStage4; - - public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { - super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); - this.sdkg = sdkg; - this.messageHandler = new MessageHandler(); - this.user.setMessageHandler(this.messageHandler); - this.parties = sdkg.getParties(); - this.arithmetic = new Fp(sdkg.getQ()); - this.isStage4 = false; - } - - /** - * 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.broadcastVerificationValues(user); - sdkg.sendSecrets(user); - } - - @Override - protected void waitUntilStageOneCompleted(){ - super.waitUntilStageOneCompleted(); - // save the received commitments as verification values - BigInteger[] 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(user); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - } - - private void ys(){ - sdkg.broadcastCommitments(user); - // wait until all parties in QUAL broadcast their commitments or aborted - for (int i:QUAL) { - for(int k = 0; k <= t; k++) { - while (parties[i - 1].commitments[k] == null && !parties[i - 1].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - sdkg.broadcastComplaints(user,QUAL); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - - // wait until all parties in QUAL done or aborted - for (int i:QUAL) { - while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - - // broadcast i private secret foreach i in QUAL that aborted - for (int i:QUAL) { - if(parties[i - 1].aborted){ - sdkg.broadcastAnswer(user, parties[i - 1].share, parties[i - 1].shareT, i); - } - } - // wait until at least t + 1 secrets will received foreach i in QUAL that aborted - for (int i:QUAL) { - if(parties[i - 1].aborted){ - while (parties[i - 1].restoreSharesSet.size() <= t) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - // restore necessary information - for (int i = 0; i < n ; i++) { - if(parties[i].restoreSharesSet.isEmpty()){ - continue; - } - Polynomial.Point[] shares = new Polynomial.Point[t + 1]; - int j = 0; - for (Polynomial.Point share: parties[i].restoreSharesSet){ - shares[j++] = share; - if (j >= shares.length){ - break; - } - } - Polynomial polynomial = SecretSharing.restorePolynomial(shares,arithmetic); - BigInteger[] coefficients = polynomial.getCoefficients(); - for (int k = 0 ; k <= t; k++){ - parties[i].commitments[k] = group.multiply(g,coefficients[k]); - } - parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); - } - } - - /** - * notifies mail handler that stage 4 was started - */ - protected void setStage4(){ - this.isStage4 = true; - SecureDistributedKeyGenerationMailHandler handler = - (SecureDistributedKeyGenerationMailHandler)user.getMailHandler(); - handler.setStage4(true); - } - - @Override - protected void stage4() { - setStage4(); - ys(); - super.stage4(); - } - - private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ - - /** - * as in super, with extension to double secret message - */ - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) - .build(); - return super.isValidSecretMessage(sender,isBroadcast,secretMessage); - } - - /** - * as in super, with extension to double secret message - */ - @Override - public void handelSecretMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; - if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - parties[i - 1].share = extractSecret(id, doubleSecretMessage.getSecret()); - parties[i - 1].shareT = extractSecret(id, doubleSecretMessage.getSecretT()); - } - } - - /** - * 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, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - if(!isStage4) { - DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) - .build(); - return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); - }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); - } - } - - /** - * if !isStage4 as super, with extension to double secret message - * else saves secret - */ - @Override - public void handelAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; - if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - int j = doubleSecretMessage.getJ(); - Polynomial.Point secret = extractSecret(j, doubleSecretMessage.getSecret()); - Polynomial.Point secretT = extractSecret(j, doubleSecretMessage.getSecretT()); - if (!isStage4) { - if (sdkg.isValidSecret(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.NonDisqualified; - - } else { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.Disqualified; - } - if(j == id){ - parties[i - 1].share = secret; - parties[i - 1].shareT = secretT; - } - } else { - parties[i - 1].restoreSharesSet.add(secret); - } - } - } - - /** - * 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; - } - } - - /** - * as in super with respect to protocol state - */ - @Override - public void handelDoneMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) - super.handelDoneMessage(sender, isBroadcast, message); - else{ - if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].ysDoneFlag = true; - } - } - } - - /** - * 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, - DKGMessages.DoubleSecretMessage complaintMessage){ - int i = complaintMessage.getI(); - int j = complaintMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); - } - - /** - * 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 - */ - @Override - public void handelComplaintMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) { - super.handelComplaintMessage(sender, isBroadcast, message); - }else { - DKGMessages.DoubleSecretMessage ysComplaintMessage =(DKGMessages.DoubleSecretMessage)message; - if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { - int i = ysComplaintMessage.getI(); - int j = ysComplaintMessage.getJ(); - Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); - Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); - if (sdkg.isValidSecret(secret, secretT, parties[i - 1].verifiableValues, j) - && !dkg.isValidSecret(secret,parties[i - 1].commitments, j)) { - parties[i - 1].aborted = true; - } - } - } - } - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGeneration; +import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/16/2016. + */ +public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { + + protected SecureDistributedKeyGenerationParty[] parties; + protected final SecureDistributedKeyGeneration sdkg; + private Arithmetic arithmetic; + private boolean isStage4; + + public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { + super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); + this.sdkg = sdkg; + this.messageHandler = new MessageHandler(); + this.user.setMessageHandler(this.messageHandler); + this.parties = sdkg.getParties(); + this.arithmetic = new Fp(sdkg.getQ()); + this.isStage4 = false; + } + + /** + * 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.broadcastVerificationValues(user); + sdkg.sendSecrets(user); + } + + @Override + protected void waitUntilStageOneCompleted(){ + super.waitUntilStageOneCompleted(); + // save the received commitments as verification values + BigInteger[] 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(user); + //broadcast done message after all complaints + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + } + + // TODO: ?? + private void resolveQualifyingPublicKey(){ + sdkg.broadcastCommitments(user); + // wait until all parties in QUAL broadcast their commitments or aborted + // TODO: in main run loop + for (int i:QUAL) { + for(int k = 0; k <= t; k++) { + while (parties[i - 1].commitments[k] == null && !parties[i - 1].aborted) { + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + sdkg.computeAndBroadcastComplaints(user,QUAL); + //broadcast done message after all complaints + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); + + // wait until all parties in QUAL done or aborted + for (int i:QUAL) { + while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + + // broadcast i private secret foreach i in QUAL that aborted + for (int i:QUAL) { + if(parties[i - 1].aborted){ + sdkg.broadcastAnswer(user, parties[i - 1].share, parties[i - 1].shareT, i); + } + } + // wait until at least t + 1 secrets will received foreach i in QUAL that aborted + for (int i:QUAL) { + if(parties[i - 1].aborted){ + while (parties[i - 1].restoreSharesSet.size() <= t) { + try { + Thread.sleep(SleepTime); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + // restore necessary information + for (int i = 0; i < n ; i++) { + if(parties[i].restoreSharesSet.isEmpty()){ + continue; + } + Polynomial.Point[] shares = new Polynomial.Point[t + 1]; + int j = 0; + for (Polynomial.Point share: parties[i].restoreSharesSet){ + 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[k] = group.multiply(g,coefficients[k]); + } + parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); + } + } + + /** + * notifies mail handler that stage 4 was started + */ + protected void setStage4(){ + this.isStage4 = true; + SecureDistributedKeyGenerationMailHandler handler = + (SecureDistributedKeyGenerationMailHandler)user.getMailHandler(); + handler.setStage4(true); + } + + @Override + protected void stage4() { + setStage4(); + resolveQualifyingPublicKey(); + super.stage4(); + } + + private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ + + /** + * as in super, with extension to double secret message + */ + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidSecretMessage(sender,isBroadcast,secretMessage); + } + + /** + * as in super, with extension to double secret message + */ + @Override + public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; + if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + parties[i - 1].share = extractSecret(id, doubleSecretMessage.getSecret()); + parties[i - 1].shareT = extractSecret(id, doubleSecretMessage.getSecretT()); + } + } + + /** + * 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, DKGMessages.DoubleSecretMessage doubleSecretMessage) { + if(!isStage4) { + DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); + }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); + } + } + + /** + * if !isStage4 as super, with extension to double secret message + * else saves secret + */ + @Override + public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; + if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + Polynomial.Point secret = extractSecret(j, doubleSecretMessage.getSecret()); + Polynomial.Point secretT = extractSecret(j, doubleSecretMessage.getSecretT()); + if (!isStage4) { + if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.NonDisqualified; + + } else { + parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.Disqualified; + } + if(j == id){ + parties[i - 1].share = secret; + parties[i - 1].shareT = secretT; + } + } else if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { + // TODO: Check that this is ok + parties[i - 1].restoreSharesSet.add(secret); + } + } + } + + /** + * 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; + } + } + + /** + * as in super with respect to protocol state + */ + @Override + public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { + if(!isStage4) + super.handleDoneMessage(sender, isBroadcast, message); + else{ + if(isValidDoneMessage(sender,isBroadcast)) { + parties[sender - 1].ysDoneFlag = true; + } + } + } + + /** + * 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, + DKGMessages.DoubleSecretMessage complaintMessage){ + int i = complaintMessage.getI(); + int j = complaintMessage.getJ(); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); + } + + /** + * 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 + */ + @Override + public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { + if(!isStage4) { + super.handleComplaintMessage(sender, isBroadcast, message); + }else { + DKGMessages.DoubleSecretMessage ysComplaintMessage =(DKGMessages.DoubleSecretMessage)message; + if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { + int i = ysComplaintMessage.getI(); + int j = ysComplaintMessage.getJ(); + Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); + Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); + if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j) + && !dkg.isValidSecret(secret,parties[i - 1].commitments, j)) { + parties[i - 1].aborted = true; + } + } + } + } + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java index 6fd93ce..c3fb319 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java @@ -1,66 +1,66 @@ -package ShamirSecretSharing; - -import Arithmetics.Arithmetic; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 1/28/2016. - * - * container of lagrange polynomial - * - * can't be constructed, constructor is private - * - * l = (image/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 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; - } -} +package ShamirSecretSharing; + +import Arithmetics.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 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; + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java index ac7fc79..03c8f99 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java @@ -1,207 +1,208 @@ -package ShamirSecretSharing; - -import Arithmetics.Arithmetic; - -import java.math.BigInteger; -import java.util.Arrays; - -/** - * Created by Tzlil on 1/27/2016. - */ -public class Polynomial implements Comparable { - private final int degree; - private final BigInteger[] coefficients; - private final Arithmetic arithmetic; - - /** - * constructor - * @param coefficients - * @param arithmetic - * degree set as max index such that coefficients[degree] not equals zero - */ - public Polynomial(BigInteger[] coefficients,Arithmetic arithmetic) { - int d = coefficients.length - 1; - while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){ - d--; - } - this.degree = d; - this.coefficients = coefficients; - this.arithmetic = arithmetic; - } - - /* - * use for tests - */ - @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 image(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 - */ - public static Polynomial interpolation(Point[] points, Arithmetic 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].image * factor[i] * l[i].coefficients[j] s.t i!=j) divide by product = - // = sum of l[i].image * 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 ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z - * new.image(x) = this.image(x) + other.image(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 in Z - * new.image(x) = constant * this.image(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 in Z - * new.image(x) = this.image(x) * other.image(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 image 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.image(x) - */ - public Point(BigInteger x, Polynomial polynomial) { - this.x = x; - this.y = polynomial.image(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); - } - } - -} +package ShamirSecretSharing; + +import Arithmetics.Arithmetic; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class Polynomial implements Comparable { + private final int degree; + private final BigInteger[] coefficients; + private final Arithmetic arithmetic; + + /** + * constructor + * @param coefficients + * @param arithmetic + * degree set as max index such that coefficients[degree] not equals zero + */ + public Polynomial(BigInteger[] coefficients,Arithmetic 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 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 ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z + * 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 in Z + * 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 in Z + * 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); + } + } + +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java index 0f424f9..b9c0386 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java @@ -1,112 +1,111 @@ -package ShamirSecretSharing; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; - -import java.math.BigInteger; -import java.util.Collection; -import java.util.Random; - -/** - * Created by Tzlil on 1/27/2016. - * an implementation of Shamire's secret sharing scheme - */ -public class SecretSharing{ - protected final int t; - protected final int n; - protected final BigInteger q; - 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 x secret, chosen from Zq - * @param random use for generate random polynomial - */ - public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q) { - this.q = q; - this.t = t; - this.n = n; - this.polynomial = generateRandomPolynomial(x,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.image(i)%q - */ - 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 image of interpolation(shares) at x = 0 - */ - public static BigInteger restoreSecret(Polynomial.Point[] shares,Arithmetic arithmetic) throws Exception { - return restorePolynomial(shares,arithmetic).image(BigInteger.ZERO); - } - /** - * @param shares - subset of the original shares - * - * @return interpolation(shares) - */ - public static Polynomial restorePolynomial(Polynomial.Point[] shares,Arithmetic 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; - } -} +package ShamirSecretSharing; + +import Arithmetics.Arithmetic; +import Arithmetics.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{ + protected final int t; + protected final int n; + protected final BigInteger q; + 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 x secret, chosen from Zq + * @param random use for generate random polynomial + */ + public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q) { + this.q = q; + this.t = t; + this.n = n; + this.polynomial = generateRandomPolynomial(x,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)%q + */ + 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 arithmetic) throws Exception { + 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 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; + } +} diff --git a/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java b/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java index d8eb5ef..9fcdbf6 100644 --- a/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java +++ b/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java @@ -1,13 +1,13 @@ -package UserInterface; - -import java.math.BigInteger; -import java.util.Set; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface DistributedKeyGenerationUser extends VerifiableSecretSharingUser { - - BigInteger getPublicValue(); - Set getQUAL(); -} +package UserInterface; + +import java.math.BigInteger; +import java.util.Set; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface DistributedKeyGenerationUser extends VerifiableSecretSharingUser { + + BigInteger getPublicValue(); + Set getQUAL(); +} diff --git a/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java index dc4a6e4..e5462a0 100644 --- a/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java +++ b/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java @@ -1,14 +1,14 @@ -package UserInterface; - -import ShamirSecretSharing.Polynomial; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface SecretSharingUser extends Runnable { - - Polynomial.Point getShare(); - int getID(); - int getN(); - int getT(); -} +package UserInterface; + +import ShamirSecretSharing.Polynomial; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface SecretSharingUser extends Runnable { + + Polynomial.Point getShare(); + int getID(); + int getN(); + int getT(); +} diff --git a/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java index 79cd404..a8e4e96 100644 --- a/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java +++ b/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java @@ -1,16 +1,16 @@ -package UserInterface; - -import UserInterface.SecretSharingUser; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface VerifiableSecretSharingUser extends SecretSharingUser { - - BigInteger[] getCommitments(); - BigInteger getGenerator(); - Group getGroup(); -} +package UserInterface; + +import UserInterface.SecretSharingUser; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 2/21/2016. + */ +public interface VerifiableSecretSharingUser extends SecretSharingUser { + + BigInteger[] getCommitments(); + BigInteger getGenerator(); + Group getGroup(); +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java index fff8952..897957e 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java @@ -1,68 +1,67 @@ -package FeldmanVerifiableSecretSharing; - -import Communication.Network; -import ShamirSecretSharing.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.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 verifiableSecretSharing) throws Exception { - int n = verifiableSecretSharing.getN(); - Group zpstar = verifiableSecretSharing.getGroup(); - BigInteger g = verifiableSecretSharing.getGenerator(); - Polynomial.Point[] shares = new Polynomial.Point[n]; - BigInteger[] commitments = verifiableSecretSharing.getCommitmentsArray(); - BigInteger[] verifications = new BigInteger[n]; - for (int i = 1 ; i <= shares.length; i ++){ - shares[i - 1] = verifiableSecretSharing.getShare(i); - verifications[i - 1] = VerifiableSecretSharing.verify(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]); - } - } -} +package FeldmanVerifiableSecretSharing; + +import ShamirSecretSharing.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.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 verifiableSecretSharing) throws Exception { + int n = verifiableSecretSharing.getN(); + Group zpstar = verifiableSecretSharing.getGroup(); + BigInteger g = verifiableSecretSharing.getGenerator(); + Polynomial.Point[] shares = new Polynomial.Point[n]; + BigInteger[] commitments = verifiableSecretSharing.getCommitmentsArray(); + 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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java index ad4aa4d..4dfd4a4 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java @@ -1,72 +1,72 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.Network; - -import java.math.BigInteger; -import java.util.*; - -/** - * Created by Tzlil on 3/21/2016. - */ -public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { - - private final DistributedKeyGeneration maliciousDkg; - private final Set falls; - public DKGMaliciousUserImpl(DistributedKeyGeneration dkg,DistributedKeyGeneration maliciousDKG, Network network,Set falls) { - super(dkg, network); - this.falls = falls; - this.maliciousDkg = maliciousDKG; - maliciousDKG.setParties(parties); - } - - public static Set selectFallsRandomly(Set ids, Random random){ - Set falls = new HashSet(); - ArrayList idsList = new ArrayList(); - 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 DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Random random){ - BigInteger q = dkg.getQ(); - BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - return new DistributedKeyGeneration(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() - ,dkg.getGenerator(),dkg.getGroup(),dkg.getId()); - } - - @Override - public void stage1() { - dkg.broadcastCommitments(user); - sendSecrets(); //insteadof dkg.sendSecrets(user); - } - - @Override - public void stage3() { - maliciousDkg.answerAllComplainingPlayers(user); - } - - @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(user,j); - }else { - dkg.sendSecret(user, j); - } - } - } - } - - -} +package JointFeldmanProtocol; + +import Communication.MailHandler; +import Communication.Network; + +import java.math.BigInteger; +import java.util.*; + +/** + * Created by Tzlil on 3/21/2016. + */ +public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { + + private final DistributedKeyGeneration maliciousDkg; + private final Set falls; + public DKGMaliciousUserImpl(DistributedKeyGeneration dkg,DistributedKeyGeneration maliciousDKG, Network network,Set falls) { + super(dkg, network); + this.falls = falls; + this.maliciousDkg = maliciousDKG; + maliciousDKG.setParties(parties); + } + + public static Set selectFallsRandomly(Set ids, Random random){ + Set falls = new HashSet(); + ArrayList idsList = new ArrayList(); + 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 DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Random random){ + BigInteger q = dkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + return new DistributedKeyGeneration(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() + ,dkg.getGenerator(),dkg.getGroup(),dkg.getId()); + } + + @Override + public void stage1() { + dkg.broadcastCommitments(user); + sendSecrets(); //insteadof dkg.sendSecrets(user); + } + + @Override + public void stage3() { + maliciousDkg.answerAllComplainingPlayers(user); + } + + @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(user,j); + }else { + dkg.sendSecret(user, j); + } + } + } + } + + +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java index 624aeeb..7599a53 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -1,175 +1,175 @@ -package JointFeldmanProtocol; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import UserInterface.DistributedKeyGenerationUser; -import Utils.GenerateRandomPrime; -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.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 group = new Zpstar(p); - Arithmetic arithmetic = new Fp(q); - int t = 9; - int n = 20; - - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; - 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.verify(i, testable.dkgs[i - 1].getCommitments(), group); - assert (expected.equals(verification)); - } - - - // restore the secret from shares - ArrayList sharesList = new ArrayList(); - - 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.restoreSecret(shares,arithmetic); - assert (calculatedSecret.equals(testable.secret)); - } - - @Test - public void test() throws Exception { - for (int i = 0; i < tests; i++){ - oneTest(i); - } - } - - class Testable{ - Set valids; - Set QUAL; - Set aborted; - Set malicious; - DistributedKeyGenerationUser[] dkgs; - Thread[] threads; - BigInteger g; - BigInteger secret; - - public Testable(Random random) { - this.dkgs = new DistributedKeyGenerationUserImpl[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); - this.threads = new Thread[n]; - this.g = sampleGenerator(random); - ArrayList ids = new ArrayList(); - for (int id = 1; id<= n ; id++){ - ids.add(id); - } - Network network = new Network(n); - int id; - BigInteger s; - DistributedKeyGeneration dkg; - this.secret = BigInteger.ZERO; - while (!ids.isEmpty()) { - id = ids.remove(random.nextInt(ids.size())); - s = randomIntModQ(random); - dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); - dkgs[id - 1] = randomDKGUser(id,network,dkg,random); - threads[id - 1] = new Thread(dkgs[id - 1]); - if(QUAL.contains(id)){ - this.secret = this.secret.add(s).mod(q); - } - } - - } - - public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - 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,network,abortStage); - case 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); - DistributedKeyGeneration maliciousDKG = DKGMaliciousUserImpl.generateMaliciousDKG(dkg,random); - return new DKGMaliciousUserImpl(dkg,maliciousDKG,network,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); - } - - } -} +package JointFeldmanProtocol; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import UserInterface.DistributedKeyGenerationUser; +import Utils.GenerateRandomPrime; +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.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 group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + + Testable[] testables; + + @Before + public void settings(){ + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); + } + } + + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + 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 sharesList = new ArrayList(); + + 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 { + for (int i = 0; i < tests; i++){ + oneTest(i); + } + } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] dkgs; + Thread[] threads; + BigInteger g; + BigInteger secret; + + public Testable(Random random) { + this.dkgs = new DistributedKeyGenerationUserImpl[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + Network network = new Network(n); + int id; + BigInteger s; + DistributedKeyGeneration dkg; + this.secret = BigInteger.ZERO; + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); + dkgs[id - 1] = randomDKGUser(id,network,dkg,random); + threads[id - 1] = new Thread(dkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUserImpl(dkg,network); + 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,network,abortStage); + case 2:// malicious + malicious.add(id); + Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); + DistributedKeyGeneration maliciousDKG = DKGMaliciousUserImpl.generateMaliciousDKG(dkg,random); + return new DKGMaliciousUserImpl(dkg,maliciousDKG,network,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); + } + + } +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java index 39f211a..6acb8ce 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java @@ -1,63 +1,63 @@ -package JointFeldmanProtocol; - -import Communication.Network; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class DKGUserImplAbort extends DistributedKeyGenerationUserImpl { - - final int abortStage; - int stage; - public DKGUserImplAbort(DistributedKeyGeneration dkg, Network network, int abortStage) { - super(dkg, network); - this.abortStage = abortStage;// 1 - 2 - this.stage = 1; - } - - - private void sendAbort(){ - user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); - } - - @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++; - } -} +package JointFeldmanProtocol; + +import Communication.Network; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class DKGUserImplAbort extends DistributedKeyGenerationUserImpl { + + final int abortStage; + int stage; + public DKGUserImplAbort(DistributedKeyGeneration dkg, Network network, int abortStage) { + super(dkg, network); + this.abortStage = abortStage;// 1 - 2 + this.stage = 1; + } + + + private void sendAbort(){ + user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java index 9240dea..a0c1d4e 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java @@ -1,64 +1,61 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.Network; -import JointFeldmanProtocol.DistributedKeyGeneration; - -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/29/2016. - */ -public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUserImpl { - - private final DistributedKeyGeneration maliciousSDKG; - private final Set falls; - public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg,SecureDistributedKeyGeneration maliciousSDKG - , Network network,Set falls) { - super(sdkg, network); - this.falls = falls; - this.maliciousSDKG = maliciousSDKG; - maliciousSDKG.setParties(parties); - } - - public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Random random){ - BigInteger q = sdkg.getQ(); - BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - return new SecureDistributedKeyGeneration(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() - ,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId()); - } - - @Override - public void stage1() { - sdkg.broadcastVerificationValues(user); - //sdkg.sendSecrets(user); - sendSecrets(); //insteadof dkg.sendSecrets(user); - } - - @Override - public void stage3() { - stopReceiver(); - maliciousSDKG.answerAllComplainingPlayers(user); - } - - @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(user,j); - }else { - sdkg.sendSecret(user, j); - } - } - } - } - -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.Network; +import JointFeldmanProtocol.DistributedKeyGeneration; + +import java.math.BigInteger; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 3/29/2016. + */ +public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUserImpl { + + private final DistributedKeyGeneration maliciousSDKG; + private final Set falls; + public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg,SecureDistributedKeyGeneration maliciousSDKG + , Network network,Set falls) { + super(sdkg, network); + this.falls = falls; + this.maliciousSDKG = maliciousSDKG; + maliciousSDKG.setParties(parties); + } + + public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Random random){ + BigInteger q = sdkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + return new SecureDistributedKeyGeneration(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() + ,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId()); + } + + @Override + public void stage1() { + sdkg.broadcastVerificationValues(user); + sendSecrets(); //insteadof dkg.sendSecrets(user); + } + + @Override + public void stage3() { + stopReceiver(); + maliciousSDKG.answerAllComplainingPlayers(user); + } + + @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(user,j); + }else { + sdkg.sendSecret(user, j); + } + } + } + } + +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java index 1b1b261..647e4cf 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java @@ -1,180 +1,177 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import JointFeldmanProtocol.DKGMaliciousUserImpl; -import JointFeldmanProtocol.DKGUserImplAbort; -import JointFeldmanProtocol.DistributedKeyGeneration; -import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import UserInterface.DistributedKeyGenerationUser; -import Utils.GenerateRandomPrime; -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.HashSet; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/29/2016. - */ -public class SDKGTest { - - int tests = 10; - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - Group group = new Zpstar(p); - Arithmetic arithmetic = new Fp(q); - int t = 9; - int n = 20; - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; - 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.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.verify(i, testable.sdkgs[i - 1].getCommitments(), group); - assert (expected.equals(verification)); - } - - - // restore the secret from shares - ArrayList sharesList = new ArrayList(); - - 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.restoreSecret(shares,arithmetic); - assert (calculatedSecret.equals(testable.secret)); - } - - @Test - public void test() throws Exception { - for (int i = 0; i < tests; i++){ - oneTest(i); - } - } - - class Testable{ - Set valids; - Set QUAL; - Set aborted; - Set malicious; - DistributedKeyGenerationUser[] sdkgs; - Thread[] threads; - BigInteger g; - BigInteger h; - BigInteger secret; - - public Testable(Random random) { - this.sdkgs = new SecureDistributedKeyGenerationUserImpl[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); - this.threads = new Thread[n]; - this.g = sampleGenerator(random); - this.h = group.multiply(g,randomIntModQ(random)); - ArrayList ids = new ArrayList(); - for (int id = 1; id<= n ; id++){ - ids.add(id); - } - Network network = new Network(n); - int id; - BigInteger s; - SecureDistributedKeyGeneration sdkg; - this.secret = BigInteger.ZERO; - while (!ids.isEmpty()) { - id = ids.remove(random.nextInt(ids.size())); - s = randomIntModQ(random); - sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id); - sdkgs[id - 1] = randomSDKGUser(id,network,sdkg,random); - threads[id - 1] = new Thread(sdkgs[id - 1]); - if(QUAL.contains(id)){ - this.secret = this.secret.add(s).mod(q); - } - } - - } - - public SecureDistributedKeyGenerationUserImpl randomSDKGUser(int id,Network network, SecureDistributedKeyGeneration sdkg,Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new SecureDistributedKeyGenerationUserImpl(sdkg,network); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); - QUAL.add(id); - return new SecureDistributedKeyGenerationUserImpl(sdkg,network); - case 1:// abort - int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 - aborted.add(id); - if (abortStage > 1){ - QUAL.add(id); - } - return new SDKGUserImplAbort(sdkg,network,abortStage); - case 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); - SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,network,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); - } - - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Communication.Network; +import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; +import JointFeldmanProtocol.DKGMaliciousUserImpl; +import ShamirSecretSharing.Polynomial; +import ShamirSecretSharing.SecretSharing; +import UserInterface.DistributedKeyGenerationUser; +import Utils.GenerateRandomPrime; +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.HashSet; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 3/29/2016. + */ +public class SDKGTest { + + int tests = 10; + BigInteger p = GenerateRandomPrime.SafePrime100Bits; + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + Testable[] testables; + + @Before + public void settings(){ + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); + } + } + + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + 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.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 sharesList = new ArrayList(); + + 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 { + for (int i = 0; i < tests; i++){ + oneTest(i); + } + } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] sdkgs; + Thread[] threads; + BigInteger g; + BigInteger h; + BigInteger secret; + + public Testable(Random random) { + this.sdkgs = new SecureDistributedKeyGenerationUserImpl[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + this.h = group.multiply(g,randomIntModQ(random)); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + Network network = new Network(n); + int id; + BigInteger s; + SecureDistributedKeyGeneration sdkg; + this.secret = BigInteger.ZERO; + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id); + sdkgs[id - 1] = randomSDKGUser(id,network,sdkg,random); + threads[id - 1] = new Thread(sdkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public SecureDistributedKeyGenerationUserImpl randomSDKGUser(int id,Network network, SecureDistributedKeyGeneration sdkg,Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUserImpl(sdkg,network); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUserImpl(sdkg,network); + case 1:// abort + int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 + aborted.add(id); + if (abortStage > 1){ + QUAL.add(id); + } + return new SDKGUserImplAbort(sdkg,network,abortStage); + case 2:// malicious + malicious.add(id); + Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); + SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,random); + return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,network,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); + } + + } +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java index c2a6fbe..551de93 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java @@ -1,65 +1,65 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.Network; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { - - final int abortStage; - int stage; - public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Network network, int abortStage) { - super(sdkg, network); - this.abortStage = abortStage;// 1 - 4 - this.stage = 1; - } - - private void abort(){ - stopReceiver(); - user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); - } - - @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++; - } -} +package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; + +import Communication.Network; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; +import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { + + final int abortStage; + int stage; + public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Network network, int abortStage) { + super(sdkg, network); + this.abortStage = abortStage;// 1 - 4 + this.stage = 1; + } + + private void abort(){ + stopReceiver(); + user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java index fe4e602..a95552d 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java @@ -1,46 +1,46 @@ -package ShamirSecretSharing.PolynomialTests; -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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.image(x).equals(p1.image(x).add(p2.image(x)))); - } - - @Test - public void addTest(){ - for (int i = 0 ; i < arr1.length; i ++){ - oneTest(arr1[i],arr2[i]); - } - } -} +package ShamirSecretSharing.PolynomialTests; +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import ShamirSecretSharing.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index 97f1b8d..a222b95 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -1,68 +1,68 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.Polynomial; -import 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 arithmetic; - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - - @Before - public void settings(){ - random = new Random(); - polynomials = new Polynomial[tests]; - pointsArrays = new Polynomial.Point[tests][]; - for (int i = 0; i < polynomials.length; i++){ - polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); - pointsArrays[i] = randomPoints(polynomials[i]); - } - arithmetic = new Fp(p); - } - - public Polynomial.Point[] randomPoints(Polynomial polynomial){ - Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1]; - BigInteger x; - Set 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]); - } - } -} +package ShamirSecretSharing.PolynomialTests; + +import Arithmetics.Arithmetic; +import Arithmetics.Fp; +import Utils.GenerateRandomPolynomial; +import ShamirSecretSharing.Polynomial; +import 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 arithmetic; + BigInteger p = GenerateRandomPrime.SafePrime100Bits; + + @Before + public void settings(){ + random = new Random(); + polynomials = new Polynomial[tests]; + pointsArrays = new Polynomial.Point[tests][]; + for (int i = 0; i < polynomials.length; i++){ + polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); + pointsArrays[i] = randomPoints(polynomials[i]); + } + arithmetic = new Fp(p); + } + + public Polynomial.Point[] randomPoints(Polynomial polynomial){ + Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1]; + BigInteger x; + Set 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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java index 3a3bf1a..2f073c5 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java @@ -1,48 +1,48 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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.image(x).equals(p.image(x).multiply(c))); - } - - @Test - public void mulByConstTest(){ - for (int i = 0 ; i < arr1.length; i ++){ - oneTest(arr1[i],arr2[i]); - } - } -} +package ShamirSecretSharing.PolynomialTests; + +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import ShamirSecretSharing.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java index a7dd365..478e541 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java @@ -1,48 +1,48 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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.image(x).equals(p1.image(x).multiply(p2.image(x)))); - } - - @Test - public void mulTest(){ - for (int i = 0 ; i < arr1.length; i ++){ - oneTest(arr1[i],arr2[i]); - } - } -} +package ShamirSecretSharing.PolynomialTests; + +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import ShamirSecretSharing.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java index a74148f..40cf306 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java @@ -1,63 +1,63 @@ -package ShamirSecretSharing; - -import Arithmetics.Z; -import 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 group; - int tests = 1 << 10; - Random random; - - @Before - public void settings(){ - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - group = new Zn(p); - 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 indexes = new ArrayList(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()))); - } - assert(secret.equals(SecretSharing.restoreSecret(shares,new Z()))); - } - - @Test - public void secretSharingTest() throws Exception { - for (int i = 0 ; i < secretSharingArray.length; i ++){ - oneTest(secretSharingArray[i],secrets[i]); - } - } -} +package ShamirSecretSharing; + +import Arithmetics.Z; +import 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 group; + int tests = 1 << 10; + Random random; + + @Before + public void settings(){ + BigInteger p = GenerateRandomPrime.SafePrime100Bits; + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + group = new Zn(p); + 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 indexes = new ArrayList(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()))); + } + assert(secret.equals(SecretSharing.recoverSecret(shares,new Z()))); + } + + @Test + public void secretSharingTest() throws Exception { + for (int i = 0 ; i < secretSharingArray.length; i ++){ + oneTest(secretSharingArray[i],secrets[i]); + } + } +} diff --git a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java index d59d051..4ca7b6a 100644 --- a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java +++ b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java @@ -1,31 +1,31 @@ -package Utils; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import ShamirSecretSharing.Polynomial; - -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 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 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 - - 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' + 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:11.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 + } + } + } +} + + + diff --git a/meerkat-common/src/main/java/Demo.java b/meerkat-common/src/main/java/Demo.java index 130adcc..9f5f379 100644 --- a/meerkat-common/src/main/java/Demo.java +++ b/meerkat-common/src/main/java/Demo.java @@ -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 + } + } +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index c51e561..c3c875c 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -1,54 +1,54 @@ -package meerkat.bulletinboard; - -import meerkat.comm.*; -import meerkat.protobuf.Voting.*; - -import static meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * Created by talm on 24/10/15. - */ -public interface BulletinBoardClient { - - interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - - /** - * 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 - * @param msg - */ - MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); - - /** - * Check how "safe" a given message is - * @param id - * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) - */ - void getRedundancy(MessageID id, ClientCallback callback); - - /** - * Read all messages posted matching the given filter - * 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). - */ - void readMessages(MessageFilterList filterList, ClientCallback> callback); - - /** - * Closes all connections, if any. - * This is done in a synchronous (blocking) way. - */ - void close(); - -} +package meerkat.bulletinboard; + +import meerkat.comm.*; +import meerkat.protobuf.Voting.*; + +import static meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by talm on 24/10/15. + */ +public interface BulletinBoardClient { + + interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + /** + * 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 + * @param msg + */ + MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + + /** + * Check how "safe" a given message is + * @param id + * @return a normalized "redundancy score" from 0 (local only) to 1 (fully published) + */ + void getRedundancy(MessageID id, ClientCallback callback); + + /** + * Read all messages posted matching the given filter + * 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). + */ + void readMessages(MessageFilterList filterList, ClientCallback> callback); + + /** + * Closes all connections, if any. + * This is done in a synchronous (blocking) way. + */ + void close(); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index da53c1f..741cb61 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -1,42 +1,42 @@ -package meerkat.bulletinboard; - -import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.*; - -/** - * 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 filter return only messages that match the filter (empty list means no filtering). - * @return - */ - BulletinBoardMessageList readMessages(MessageFilterList filterList) 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.protobuf.BulletinBoardAPI.*; + +/** + * 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 filter return only messages that match the filter (empty list means no filtering). + * @return + */ + BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException; + + /** + * This method closes the connection to the DB. + * @throws CommunicationException on DB connection error. + */ + public void close() throws CommunicationException; +} diff --git a/meerkat-common/src/main/java/meerkat/comm/CommunicationException.java b/meerkat-common/src/main/java/meerkat/comm/CommunicationException.java index 05e7a22..f96dced 100644 --- a/meerkat-common/src/main/java/meerkat/comm/CommunicationException.java +++ b/meerkat-common/src/main/java/meerkat/comm/CommunicationException.java @@ -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; + } +} diff --git a/meerkat-common/src/main/java/meerkat/comm/Timestamp.java b/meerkat-common/src/main/java/meerkat/comm/Timestamp.java index 6c63854..568fa86 100644 --- a/meerkat-common/src/main/java/meerkat/comm/Timestamp.java +++ b/meerkat-common/src/main/java/meerkat/comm/Timestamp.java @@ -1,7 +1,7 @@ -package meerkat.comm; - -/** - * Created by talm on 24/10/15. - */ -public class Timestamp { -} +package meerkat.comm; + +/** + * Created by talm on 24/10/15. + */ +public class Timestamp { +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java index 06b012c..c3f7ea7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -1,38 +1,38 @@ -package meerkat.crypto; - -import com.google.protobuf.Message; - -import java.security.MessageDigest; - -/** - * Created by talm on 11/9/15. - */ -public interface Digest { - /** - * Completes the hash computation by performing final operations such as padding. - * (copied from {@link MessageDigest#digest()}) - * @return - */ - byte[] digest(); - - /** - * Updates the digest using the specified message (in serialized wire form) - * - * Each message is (automatically) prepended with its length as a 32-bit big-endian unsigned integer. - * @param msg - * @return - */ - void update(Message msg); - - /** - * Resets the digest for further use. - */ - void reset(); - - /** - * Clone the current digest state - * @return - */ - public Digest clone() throws CloneNotSupportedException; - -} +package meerkat.crypto; + +import com.google.protobuf.Message; + +import java.security.MessageDigest; + +/** + * Created by talm on 11/9/15. + */ +public interface Digest { + /** + * Completes the hash computation by performing final operations such as padding. + * (copied from {@link MessageDigest#digest()}) + * @return + */ + byte[] digest(); + + /** + * Updates the digest using the specified message (in serialized wire form) + * + * Each message is (automatically) prepended with its length as a 32-bit big-endian unsigned integer. + * @param msg + * @return + */ + void update(Message msg); + + /** + * Resets the digest for further use. + */ + void reset(); + + /** + * Clone the current digest state + * @return + */ + public Digest clone() throws CloneNotSupportedException; + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java index e7b64e5..3785235 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java @@ -1,96 +1,96 @@ -package meerkat.crypto; - -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; - -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import static meerkat.protobuf.Crypto.*; - -/** - * Created by talm on 25/10/15. - * - * Sign and verify arrays of messages - */ -public interface DigitalSignature { - final public static String CERTIFICATE_ENCODING_X509 = "X.509"; - - /** - * Load a set of certificates from an input stream. - * This will consume the entire stream. - * Certificates can be either DER-encoded (binary) or PEM (base64) encoded. - * This may be called multiple times to load several different certificates. - * It must be called before calling {@link #verify()}. - * @param certStream source from which certificates are loaded - * @throws CertificateException on parsing errors - */ - public void loadVerificationCertificates(InputStream certStream) - throws CertificateException; - - /** - * Clear the loaded verification certificates. - */ - public void clearVerificationCertificates(); - - - /** - * Add msg to the content stream to be verified / signed. Each message is (automatically) - * prepended with its length as a 32-bit big-endian unsigned integer. - * - * @param msg - * @throws SignatureException - */ - public void updateContent(Message msg) throws SignatureException; - - - /** - * Sign the content that was added using {@link #updateContent(Message)}. - * Reset the DigitalSignature and make it available to sign a new message using the same key. - * @return - * @throws SignatureException - */ - Signature sign() throws SignatureException; - - /** - * Initialize the verifier with the certificate whose Id is in sig. - * @param sig - * @throws CertificateException - * @throws InvalidKeyException - */ - void initVerify(Signature sig) - throws CertificateException, InvalidKeyException; - - /** - * Verify the updated content using the initialized signature. - * @return - */ - public boolean verify(); - - /** - * Loads a private signing key. The keystore must include both the public and private - * key parts. - * This method must be called before calling {@link #sign()} or {@link #updateContent(Message)} - * Calling this method again will replace the key. - * - * @param keyStoreBuilder A keystore builder that can be used to load a keystore. - */ - public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) - throws IOException, CertificateException, UnrecoverableKeyException; - - - /** - * @return the signer ID if it exists; null otherwise. - */ - public ByteString getSignerID(); - - /** - * Clear the signing key (will require authentication to use again). - */ - public void clearSigningKey(); - -} +package meerkat.crypto; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import static meerkat.protobuf.Crypto.*; + +/** + * Created by talm on 25/10/15. + * + * Sign and verify arrays of messages + */ +public interface DigitalSignature { + final public static String CERTIFICATE_ENCODING_X509 = "X.509"; + + /** + * Load a set of certificates from an input stream. + * This will consume the entire stream. + * Certificates can be either DER-encoded (binary) or PEM (base64) encoded. + * This may be called multiple times to load several different certificates. + * It must be called before calling {@link #verify()}. + * @param certStream source from which certificates are loaded + * @throws CertificateException on parsing errors + */ + public void loadVerificationCertificates(InputStream certStream) + throws CertificateException; + + /** + * Clear the loaded verification certificates. + */ + public void clearVerificationCertificates(); + + + /** + * Add msg to the content stream to be verified / signed. Each message is (automatically) + * prepended with its length as a 32-bit big-endian unsigned integer. + * + * @param msg + * @throws SignatureException + */ + public void updateContent(Message msg) throws SignatureException; + + + /** + * Sign the content that was added using {@link #updateContent(Message)}. + * Reset the DigitalSignature and make it available to sign a new message using the same key. + * @return + * @throws SignatureException + */ + Signature sign() throws SignatureException; + + /** + * Initialize the verifier with the certificate whose Id is in sig. + * @param sig + * @throws CertificateException + * @throws InvalidKeyException + */ + void initVerify(Signature sig) + throws CertificateException, InvalidKeyException; + + /** + * Verify the updated content using the initialized signature. + * @return + */ + public boolean verify(); + + /** + * Loads a private signing key. The keystore must include both the public and private + * key parts. + * This method must be called before calling {@link #sign()} or {@link #updateContent(Message)} + * Calling this method again will replace the key. + * + * @param keyStoreBuilder A keystore builder that can be used to load a keystore. + */ + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) + throws IOException, CertificateException, UnrecoverableKeyException; + + + /** + * @return the signer ID if it exists; null otherwise. + */ + public ByteString getSignerID(); + + /** + * Clear the signing key (will require authentication to use again). + */ + public void clearSigningKey(); + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/Encryption.java b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java index 6a40d0d..0628685 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Encryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java @@ -1,40 +1,40 @@ -package meerkat.crypto; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; - -import java.io.IOException; -import java.util.Random; - -import static meerkat.protobuf.Crypto.*; - -/** - * Created by talm on 11/2/15. - */ -public interface Encryption { - /** - * Encrypt the serialized form of a message plaintext. - * @param plaintext - * @param rnd - * @return - */ - RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException; // TODO: type of exception; throws - - - /** - * Rerandomize a ciphertext using the supplied randomness. - * @param msg - * @param rnd - * @return - * @throws InvalidProtocolBufferException - */ - RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException; - - /** - * Generate randomness compatible with {@link #encrypt(Message, EncryptionRandomness) and - * {@link #rerandomize(RerandomizableEncryptedMessage, EncryptionRandomness)}}. - * @param rand - * @return - */ - EncryptionRandomness generateRandomness(Random rand); -} +package meerkat.crypto; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; + +import java.io.IOException; +import java.util.Random; + +import static meerkat.protobuf.Crypto.*; + +/** + * Created by talm on 11/2/15. + */ +public interface Encryption { + /** + * Encrypt the serialized form of a message plaintext. + * @param plaintext + * @param rnd + * @return + */ + RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException; // TODO: type of exception; throws + + + /** + * Rerandomize a ciphertext using the supplied randomness. + * @param msg + * @param rnd + * @return + * @throws InvalidProtocolBufferException + */ + RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException; + + /** + * Generate randomness compatible with {@link #encrypt(Message, EncryptionRandomness) and + * {@link #rerandomize(RerandomizableEncryptedMessage, EncryptionRandomness)}}. + * @param rand + * @return + */ + EncryptionRandomness generateRandomness(Random rand); +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java index 0afbdd7..1102c22 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java @@ -1,134 +1,134 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Crypto.Signature; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ECPrivateKeyParameters; -import org.bouncycastle.crypto.signers.DSAKCalculator; -import org.bouncycastle.crypto.signers.ECDSASigner; -import org.bouncycastle.crypto.signers.HMacDSAKCalculator; -import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.*; -import java.security.cert.*; -import java.security.interfaces.ECPrivateKey; - - -/** - * Sign and verify digital signatures. - * - * Uses deterministic ECDSA signatures as per RFC 6979 - * - * This class uses BouncyCastle directly, so will not work with arbitrary PKCS11 providers. - * - * This class is not thread-safe (each thread should have its own instance). - */ -public class ECDSADeterministicSignature extends ECDSASignature { - final Logger logger = LoggerFactory.getLogger(getClass()); - - /** - * Digest of message contents for deterministic signing. - */ - SHA256Digest msgDigest = new SHA256Digest(); - - /** - * The actual signing implementation. (used only signing -- superclass is used for verification) - */ - ECDSASigner deterministicSigner; - - /** - * Output the DER encoding of the ASN.1 sequence r,s - * @param r - * @param s - * @return - */ - public static byte[] derEncodeSignature(BigInteger r, BigInteger s) { - ASN1Integer[] rs = {new ASN1Integer(r), new ASN1Integer(s)}; - DERSequence seq = new DERSequence(rs); - - try { - return seq.getEncoded(); - } catch (IOException e) { - throw new RuntimeException("Should never happen! DER Encoding exception", e); - } - } - - public ECDSADeterministicSignature() { - DSAKCalculator kCalk = new HMacDSAKCalculator(new org.bouncycastle.crypto.digests.SHA256Digest()); - deterministicSigner = new ECDSASigner(kCalk); - } - - @Override - public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) - throws CertificateException, UnrecoverableKeyException, IOException { - super.loadSigningCertificate(keyStoreBuilder); - - if (!(loadedSigningKey instanceof ECPrivateKey)) { - logger.error("Wrong private key type (expected ECPrivateKey, got {})", loadedSigningKey.getClass()); - throw new CertificateException("Wrong signing key type!"); - } - ECPrivateKey key = (ECPrivateKey) loadedSigningKey; - - AsymmetricKeyParameter baseParams; - try { - baseParams = ECUtil.generatePrivateKeyParameter(key); - } catch (InvalidKeyException e) { - throw new UnrecoverableKeyException("Couldn't convert private key"); - } - - if (!(baseParams instanceof ECPrivateKeyParameters)) { - logger.error("Error converting to bouncycastle type! (got {})", baseParams.getClass()); - throw new UnrecoverableKeyException("Wrong signing key type!"); - } - - ECPrivateKeyParameters params = (ECPrivateKeyParameters) baseParams; - - deterministicSigner.init(true, params); - } - - /** - * Add the list of messages to the stream that is being verified/signed. - * Messages are prepended with their length in 32-bit big-endian format. - * - * @param msg - * @throws SignatureException - */ - @Override - public void updateContent(Message msg) throws SignatureException { - assert msg != null; - - // We're doing twice the digest work so that we also support verification with the same update. - // If this becomes a problem, we can decide which way to update based on which init was called. - super.updateContent(msg); - msgDigest.update(msg); - } - - @Override - public void updateContent(InputStream in) throws IOException, SignatureException { - ByteString inStr = ByteString.readFrom(in); - signer.update(inStr.asReadOnlyByteBuffer()); - msgDigest.update(inStr); - } - - @Override - public Signature sign() throws SignatureException { - Signature.Builder sig = Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - - BigInteger[] rawSig = deterministicSigner.generateSignature(msgDigest.digest()); - - sig.setData(ByteString.copyFrom(derEncodeSignature(rawSig[0], rawSig[1]))); - - sig.setSignerId(loadedSigningKeyId); - return sig.build(); - } -} +package meerkat.crypto.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Crypto.Signature; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.signers.DSAKCalculator; +import org.bouncycastle.crypto.signers.ECDSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.security.interfaces.ECPrivateKey; + + +/** + * Sign and verify digital signatures. + * + * Uses deterministic ECDSA signatures as per RFC 6979 + * + * This class uses BouncyCastle directly, so will not work with arbitrary PKCS11 providers. + * + * This class is not thread-safe (each thread should have its own instance). + */ +public class ECDSADeterministicSignature extends ECDSASignature { + final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * Digest of message contents for deterministic signing. + */ + SHA256Digest msgDigest = new SHA256Digest(); + + /** + * The actual signing implementation. (used only signing -- superclass is used for verification) + */ + ECDSASigner deterministicSigner; + + /** + * Output the DER encoding of the ASN.1 sequence r,s + * @param r + * @param s + * @return + */ + public static byte[] derEncodeSignature(BigInteger r, BigInteger s) { + ASN1Integer[] rs = {new ASN1Integer(r), new ASN1Integer(s)}; + DERSequence seq = new DERSequence(rs); + + try { + return seq.getEncoded(); + } catch (IOException e) { + throw new RuntimeException("Should never happen! DER Encoding exception", e); + } + } + + public ECDSADeterministicSignature() { + DSAKCalculator kCalk = new HMacDSAKCalculator(new org.bouncycastle.crypto.digests.SHA256Digest()); + deterministicSigner = new ECDSASigner(kCalk); + } + + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) + throws CertificateException, UnrecoverableKeyException, IOException { + super.loadSigningCertificate(keyStoreBuilder); + + if (!(loadedSigningKey instanceof ECPrivateKey)) { + logger.error("Wrong private key type (expected ECPrivateKey, got {})", loadedSigningKey.getClass()); + throw new CertificateException("Wrong signing key type!"); + } + ECPrivateKey key = (ECPrivateKey) loadedSigningKey; + + AsymmetricKeyParameter baseParams; + try { + baseParams = ECUtil.generatePrivateKeyParameter(key); + } catch (InvalidKeyException e) { + throw new UnrecoverableKeyException("Couldn't convert private key"); + } + + if (!(baseParams instanceof ECPrivateKeyParameters)) { + logger.error("Error converting to bouncycastle type! (got {})", baseParams.getClass()); + throw new UnrecoverableKeyException("Wrong signing key type!"); + } + + ECPrivateKeyParameters params = (ECPrivateKeyParameters) baseParams; + + deterministicSigner.init(true, params); + } + + /** + * Add the list of messages to the stream that is being verified/signed. + * Messages are prepended with their length in 32-bit big-endian format. + * + * @param msg + * @throws SignatureException + */ + @Override + public void updateContent(Message msg) throws SignatureException { + assert msg != null; + + // We're doing twice the digest work so that we also support verification with the same update. + // If this becomes a problem, we can decide which way to update based on which init was called. + super.updateContent(msg); + msgDigest.update(msg); + } + + @Override + public void updateContent(InputStream in) throws IOException, SignatureException { + ByteString inStr = ByteString.readFrom(in); + signer.update(inStr.asReadOnlyByteBuffer()); + msgDigest.update(inStr); + } + + @Override + public Signature sign() throws SignatureException { + Signature.Builder sig = Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + + BigInteger[] rawSig = deterministicSigner.generateSignature(msgDigest.digest()); + + sig.setData(ByteString.copyFrom(derEncodeSignature(rawSig[0], rawSig[1]))); + + sig.setSignerId(loadedSigningKeyId); + return sig.build(); + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 887b8e8..84017e0 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -1,322 +1,322 @@ -package meerkat.crypto.concrete; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.security.*; -import java.security.cert.*; -import java.security.cert.Certificate; -import java.util.*; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Crypto; -import meerkat.util.Hex; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.protobuf.Message; - -import meerkat.crypto.DigitalSignature; -import meerkat.protobuf.Crypto.Signature; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; - - -/** - * Sign and verify digital signatures. - * - * This class is not thread-safe (each thread should have its own instance). - */ -public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature { - final Logger logger = LoggerFactory.getLogger(getClass()); - - final public static String KEYSTORE_TYPE = "PKCS12"; - final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA"; - - SHA256Digest certDigest = new SHA256Digest(); - - /** - * Buffer used to hold length in for hash update - */ - ByteBuffer lenBuf = ByteBuffer.allocate(4); - - - Map loadedCertificates = new HashMap<>(); - - /** - * Signature currently loaded (will be used in calls to {@link #verify()}). - */ - ByteString loadedSignature = null; - - ByteString loadedSigningKeyId = null; - - /** - * The actual signing implementation. (used for both signing and verifying) - */ - java.security.Signature signer; - - /** - * The currently loaded signing key. - */ - PrivateKey loadedSigningKey; - - - /** - * Compute a fingerprint of a cert as a SHA256 hash. - * - * @param cert - * @return - */ - public ByteString computeCertificateFingerprint(Certificate cert) { - try { - certDigest.reset(); - byte[] data = cert.getEncoded(); - certDigest.update(data); - return ByteString.copyFrom(certDigest.digest()); - } catch (CertificateEncodingException e) { - // Shouldn't happen - logger.error("Certificate encoding error", e); - throw new RuntimeException("Certificate encoding error", e); - } - - } - - public ECDSASignature(java.security.Signature signer) { - this.signer = signer; - } - - public ECDSASignature() { - try { - this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - // Should never happen - logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e); - } - } - - @Override - public void loadVerificationCertificates(InputStream certStream) - throws CertificateException { - CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509); - Collection certs = certificateFactory.generateCertificates(certStream); - for (Certificate cert : certs) { - // Just checking - if (!(cert instanceof X509Certificate)) { - logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName()); - continue; - } - ByteString keyId = computeCertificateFingerprint(cert); - loadedCertificates.put(keyId, cert); - } - } - - @Override - public void clearVerificationCertificates() { - loadedCertificates.clear(); - } - - - /** - * Add the list of messages to the stream that is being verified/signed. - * Messages are prepended with their length in 32-bit big-endian format. - * - * @param msg - * @throws SignatureException - */ - @Override - public void updateContent(Message msg) throws SignatureException { - assert msg != null; - - lenBuf.clear(); - lenBuf.putInt(msg.getSerializedSize()); - lenBuf.flip(); - signer.update(lenBuf); - signer.update(msg.toByteString().asReadOnlyByteBuffer()); - } - - public void updateContent(InputStream in) throws IOException, SignatureException { - ByteString inStr = ByteString.readFrom(in); - signer.update(inStr.asReadOnlyByteBuffer()); - } - - @Override - public Signature sign() throws SignatureException { - Signature.Builder sig = Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setData(ByteString.copyFrom(signer.sign())); - sig.setSignerId(loadedSigningKeyId); - return sig.build(); - } - - @Override - public void initVerify(Signature sig) - throws CertificateException, InvalidKeyException { - Certificate cert = loadedCertificates.get(sig.getSignerId()); - if (cert == null) { - logger.warn("No certificate loaded for ID {}!", sig.getSignerId()); - throw new CertificateException("No certificate loaded for " + sig.getSignerId()); - } - signer.initVerify(cert.getPublicKey()); - loadedSignature = sig.getData(); - loadedSigningKeyId = null; - } - - @Override - public boolean verify() { - try { - return signer.verify(loadedSignature.toByteArray()); - } catch (SignatureException e) { - // Happens only if signature is invalid! - logger.error("Signature exception", e); - return false; - } - } - - /** - * Utility method to more easily deal with simple password-protected files. - * - * @param password - * @return - */ - public CallbackHandler getFixedPasswordHandler(final char[] password) { - return new CallbackHandler() { - @Override - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof PasswordCallback) { - PasswordCallback passwordCallback = (PasswordCallback) callback; - logger.debug("Requested password ({})", passwordCallback.getPrompt()); - passwordCallback.setPassword(password); - } - } - - } - }; - } - - /** - * Load a keystore from an input stream in PKCS12 format. - * - * @param keyStream - * @param password - * @return - * @throws IOException - * @throws CertificateException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - */ - public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) - throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { - KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); - keyStore.load(keyStream, password); - return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password))); - } - - - /** - * For now we only support PKCS12. - * TODO: Support for PKCS11 as well. - * - * @param keyStoreBuilder - * @throws IOException - * @throws CertificateException - * @throws UnrecoverableKeyException - */ - @Override - public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) - throws IOException, CertificateException, UnrecoverableKeyException { - try { - - KeyStore keyStore = keyStoreBuilder.getKeyStore(); - - // Iterate through all aliases until we find the first privatekey - Enumeration aliases = keyStore.aliases(); - while (aliases.hasMoreElements()) { - String alias = aliases.nextElement(); - logger.trace("Testing keystore entry {}", alias); - - - try { - Certificate cert = keyStore.getCertificate(alias); - logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass()); - - Key key; - - try { - key = keyStore.getKey(alias, null); - } catch (UnrecoverableKeyException e) { - // This might be a keystore that doesn't support callback handlers - // (e.g., Java 8 PKCS12) - // Manually extract password using callback handler - char[] password = null; - KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias); - - if (prot instanceof KeyStore.PasswordProtection) { - password = ((KeyStore.PasswordProtection) prot).getPassword(); - } else if (prot instanceof KeyStore.CallbackHandlerProtection) { - PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false); - Callback[] callbacks = { callback }; - try { - ((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks); - password = callback.getPassword(); - } catch (UnsupportedCallbackException e1) { - logger.error("PasswordCallback fallback not supported!", e1); - throw new UnrecoverableKeyException("Couldn't use password callback to get key"); - } - } else { - logger.error("Unrecognized protection handler for keystore: {}", prot.getClass()); - throw new UnrecoverableKeyException("Unrecognized protection handler for keystore"); - } - key = keyStore.getKey(alias, password); - } - logger.trace("keystore entry {}, has key type {}", alias, key.getClass()); - if (key instanceof PrivateKey) { - loadedSigningKey = (PrivateKey) key; - loadedSigningKeyId = computeCertificateFingerprint(cert); - signer.initSign(loadedSigningKey); - logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId)); - - return; - } else { - logger.info("Certificate {} in keystore does not have a private key", cert.toString()); - } - } catch(InvalidKeyException e) { - logger.info("Read invalid key", e); - } catch(UnrecoverableEntryException e) { - logger.info("Read unrecoverable entry", e); - } - } - - } catch (KeyStoreException e) { - logger.error("Keystore exception", e); - } catch (NoSuchAlgorithmException e) { - logger.error("NoSuchAlgorithmException exception", e); - throw new CertificateException(e); - } - logger.error("Didn't find valid private key entry in keystore"); - throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!"); - } - - @Override - public ByteString getSignerID() { - return loadedSigningKeyId; - } - - public void clearSigningKey() { - try { - // TODO: Check if this really clears the key from memory - if (loadedSigningKeyId != null) - signer.initSign(null); - loadedSigningKeyId = null; - loadedSigningKey = null; - // Start garbage collection? - } catch (InvalidKeyException e) { - // Do nothing - } - } - - -} +package meerkat.crypto.concrete; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.util.*; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto; +import meerkat.util.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.protobuf.Message; + +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.Crypto.Signature; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + + +/** + * Sign and verify digital signatures. + * + * This class is not thread-safe (each thread should have its own instance). + */ +public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature { + final Logger logger = LoggerFactory.getLogger(getClass()); + + final public static String KEYSTORE_TYPE = "PKCS12"; + final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA"; + + SHA256Digest certDigest = new SHA256Digest(); + + /** + * Buffer used to hold length in for hash update + */ + ByteBuffer lenBuf = ByteBuffer.allocate(4); + + + Map loadedCertificates = new HashMap<>(); + + /** + * Signature currently loaded (will be used in calls to {@link #verify()}). + */ + ByteString loadedSignature = null; + + ByteString loadedSigningKeyId = null; + + /** + * The actual signing implementation. (used for both signing and verifying) + */ + java.security.Signature signer; + + /** + * The currently loaded signing key. + */ + PrivateKey loadedSigningKey; + + + /** + * Compute a fingerprint of a cert as a SHA256 hash. + * + * @param cert + * @return + */ + public ByteString computeCertificateFingerprint(Certificate cert) { + try { + certDigest.reset(); + byte[] data = cert.getEncoded(); + certDigest.update(data); + return ByteString.copyFrom(certDigest.digest()); + } catch (CertificateEncodingException e) { + // Shouldn't happen + logger.error("Certificate encoding error", e); + throw new RuntimeException("Certificate encoding error", e); + } + + } + + public ECDSASignature(java.security.Signature signer) { + this.signer = signer; + } + + public ECDSASignature() { + try { + this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + // Should never happen + logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e); + } + } + + @Override + public void loadVerificationCertificates(InputStream certStream) + throws CertificateException { + CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509); + Collection certs = certificateFactory.generateCertificates(certStream); + for (Certificate cert : certs) { + // Just checking + if (!(cert instanceof X509Certificate)) { + logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName()); + continue; + } + ByteString keyId = computeCertificateFingerprint(cert); + loadedCertificates.put(keyId, cert); + } + } + + @Override + public void clearVerificationCertificates() { + loadedCertificates.clear(); + } + + + /** + * Add the list of messages to the stream that is being verified/signed. + * Messages are prepended with their length in 32-bit big-endian format. + * + * @param msg + * @throws SignatureException + */ + @Override + public void updateContent(Message msg) throws SignatureException { + assert msg != null; + + lenBuf.clear(); + lenBuf.putInt(msg.getSerializedSize()); + lenBuf.flip(); + signer.update(lenBuf); + signer.update(msg.toByteString().asReadOnlyByteBuffer()); + } + + public void updateContent(InputStream in) throws IOException, SignatureException { + ByteString inStr = ByteString.readFrom(in); + signer.update(inStr.asReadOnlyByteBuffer()); + } + + @Override + public Signature sign() throws SignatureException { + Signature.Builder sig = Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setData(ByteString.copyFrom(signer.sign())); + sig.setSignerId(loadedSigningKeyId); + return sig.build(); + } + + @Override + public void initVerify(Signature sig) + throws CertificateException, InvalidKeyException { + Certificate cert = loadedCertificates.get(sig.getSignerId()); + if (cert == null) { + logger.warn("No certificate loaded for ID {}!", sig.getSignerId()); + throw new CertificateException("No certificate loaded for " + sig.getSignerId()); + } + signer.initVerify(cert.getPublicKey()); + loadedSignature = sig.getData(); + loadedSigningKeyId = null; + } + + @Override + public boolean verify() { + try { + return signer.verify(loadedSignature.toByteArray()); + } catch (SignatureException e) { + // Happens only if signature is invalid! + logger.error("Signature exception", e); + return false; + } + } + + /** + * Utility method to more easily deal with simple password-protected files. + * + * @param password + * @return + */ + public CallbackHandler getFixedPasswordHandler(final char[] password) { + return new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof PasswordCallback) { + PasswordCallback passwordCallback = (PasswordCallback) callback; + logger.debug("Requested password ({})", passwordCallback.getPrompt()); + passwordCallback.setPassword(password); + } + } + + } + }; + } + + /** + * Load a keystore from an input stream in PKCS12 format. + * + * @param keyStream + * @param password + * @return + * @throws IOException + * @throws CertificateException + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + */ + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) + throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { + KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + keyStore.load(keyStream, password); + return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password))); + } + + + /** + * For now we only support PKCS12. + * TODO: Support for PKCS11 as well. + * + * @param keyStoreBuilder + * @throws IOException + * @throws CertificateException + * @throws UnrecoverableKeyException + */ + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) + throws IOException, CertificateException, UnrecoverableKeyException { + try { + + KeyStore keyStore = keyStoreBuilder.getKeyStore(); + + // Iterate through all aliases until we find the first privatekey + Enumeration aliases = keyStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + logger.trace("Testing keystore entry {}", alias); + + + try { + Certificate cert = keyStore.getCertificate(alias); + logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass()); + + Key key; + + try { + key = keyStore.getKey(alias, null); + } catch (UnrecoverableKeyException e) { + // This might be a keystore that doesn't support callback handlers + // (e.g., Java 8 PKCS12) + // Manually extract password using callback handler + char[] password = null; + KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias); + + if (prot instanceof KeyStore.PasswordProtection) { + password = ((KeyStore.PasswordProtection) prot).getPassword(); + } else if (prot instanceof KeyStore.CallbackHandlerProtection) { + PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false); + Callback[] callbacks = { callback }; + try { + ((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks); + password = callback.getPassword(); + } catch (UnsupportedCallbackException e1) { + logger.error("PasswordCallback fallback not supported!", e1); + throw new UnrecoverableKeyException("Couldn't use password callback to get key"); + } + } else { + logger.error("Unrecognized protection handler for keystore: {}", prot.getClass()); + throw new UnrecoverableKeyException("Unrecognized protection handler for keystore"); + } + key = keyStore.getKey(alias, password); + } + logger.trace("keystore entry {}, has key type {}", alias, key.getClass()); + if (key instanceof PrivateKey) { + loadedSigningKey = (PrivateKey) key; + loadedSigningKeyId = computeCertificateFingerprint(cert); + signer.initSign(loadedSigningKey); + logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId)); + + return; + } else { + logger.info("Certificate {} in keystore does not have a private key", cert.toString()); + } + } catch(InvalidKeyException e) { + logger.info("Read invalid key", e); + } catch(UnrecoverableEntryException e) { + logger.info("Read unrecoverable entry", e); + } + } + + } catch (KeyStoreException e) { + logger.error("Keystore exception", e); + } catch (NoSuchAlgorithmException e) { + logger.error("NoSuchAlgorithmException exception", e); + throw new CertificateException(e); + } + logger.error("Didn't find valid private key entry in keystore"); + throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!"); + } + + @Override + public ByteString getSignerID() { + return loadedSigningKeyId; + } + + public void clearSigningKey() { + try { + // TODO: Check if this really clears the key from memory + if (loadedSigningKeyId != null) + signer.initSign(null); + loadedSigningKeyId = null; + loadedSigningKey = null; + // Start garbage collection? + } catch (InvalidKeyException e) { + // Do nothing + } + } + + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 6258f5f..05447c9 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -1,135 +1,135 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.Encryption; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.crypto.params.ECKeyParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.crypto.util.PublicKeyFactory; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; -import org.bouncycastle.util.BigIntegers; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.util.PRGRandom; -import org.factcenter.qilin.util.Pair; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.spec.*; -import java.util.Random; - -/** - * Created by talm on 17/11/15. - */ -public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { - final Logger logger = LoggerFactory.getLogger(getClass()); - - public final static String KEY_ALGORITHM = "ECDH"; - - /** - * The Qilin format El-Gamal public key - */ - ECElGamal.PK elGamalPK; - - ECCurve curve; - - ECGroup group; - - public ECGroup getGroup() { return group; } - - public ECElGamal.PK getElGamalPK() { - return elGamalPK; - } - - public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException { - AsymmetricKeyParameter keyParam; - - try { - keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray()); - } catch (IOException e) { - // Shouldn't every happen - logger.error("Invalid Public Key Encoding", e); - throw new InvalidKeySpecException("Invalid Public Key Encoding", e); - } - - if (!(keyParam instanceof ECPublicKeyParameters)) { - logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass()); - throw new InvalidKeySpecException("Not a valid EC public key!"); - } - - ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters(); - ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(), - params.getSeed()); - - curve = params.getCurve(); - group = new ECGroup(ecParams); - - elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); - } - - - @Override - public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { - - // We write the message using writeDelimited to so the length gets prepended. - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - plaintext.writeDelimitedTo(out); - } catch (IOException e) { - logger.error("Should never happen!", e); - throw new RuntimeException("Error in ByteArrayOutputStream!", e); - } - byte[] msg = out.toByteArray(); - ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg)); - - BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); - Pair cipherText = elGamalPK.encrypt(encodedMsg, rndInt); - ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() - .setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) - .setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) - .build(); - - return Crypto.RerandomizableEncryptedMessage.newBuilder() - .setData(encodedCipherText.toByteString()) - .build(); - } - - @Override - public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { - BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); - Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); - ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); - - Pair originalCipher = new Pair( - curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), - curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); - Pair newCipher = elGamalPK.add(originalCipher, randomizer); - - return Crypto.RerandomizableEncryptedMessage.newBuilder() - .setData( - ConcreteCrypto.ElGamalCiphertext.newBuilder() - .setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) - .setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) - .build().toByteString() - ).build(); - } - - @Override - public Crypto.EncryptionRandomness generateRandomness(Random rand) { - BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand); - Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder() - .setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build(); - - return retval; - } -} +package meerkat.crypto.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.Encryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.util.PRGRandom; +import org.factcenter.qilin.util.Pair; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.spec.*; +import java.util.Random; + +/** + * Created by talm on 17/11/15. + */ +public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { + final Logger logger = LoggerFactory.getLogger(getClass()); + + public final static String KEY_ALGORITHM = "ECDH"; + + /** + * The Qilin format El-Gamal public key + */ + ECElGamal.PK elGamalPK; + + ECCurve curve; + + ECGroup group; + + public ECGroup getGroup() { return group; } + + public ECElGamal.PK getElGamalPK() { + return elGamalPK; + } + + public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException { + AsymmetricKeyParameter keyParam; + + try { + keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray()); + } catch (IOException e) { + // Shouldn't every happen + logger.error("Invalid Public Key Encoding", e); + throw new InvalidKeySpecException("Invalid Public Key Encoding", e); + } + + if (!(keyParam instanceof ECPublicKeyParameters)) { + logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass()); + throw new InvalidKeySpecException("Not a valid EC public key!"); + } + + ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters(); + ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(), + params.getSeed()); + + curve = params.getCurve(); + group = new ECGroup(ecParams); + + elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); + } + + + @Override + public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { + + // We write the message using writeDelimited to so the length gets prepended. + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + plaintext.writeDelimitedTo(out); + } catch (IOException e) { + logger.error("Should never happen!", e); + throw new RuntimeException("Error in ByteArrayOutputStream!", e); + } + byte[] msg = out.toByteArray(); + ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg)); + + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair cipherText = elGamalPK.encrypt(encodedMsg, rndInt); + ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) + .setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) + .build(); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData(encodedCipherText.toByteString()) + .build(); + } + + @Override + public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); + ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); + + Pair originalCipher = new Pair( + curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), + curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); + Pair newCipher = elGamalPK.add(originalCipher, randomizer); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData( + ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) + .setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) + .build().toByteString() + ).build(); + } + + @Override + public Crypto.EncryptionRandomness generateRandomness(Random rand) { + BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand); + Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder() + .setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build(); + + return retval; + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java index 4f2e7a5..ca09689 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java @@ -1,43 +1,43 @@ -package meerkat.crypto.concrete; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.security.Provider; -import java.security.Security; - -/** - * A class that performs required crypto setup - */ -public class GlobalCryptoSetup { - final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); - - static boolean loadedBouncyCastle = false; - static Provider bouncyCastleProvider; - - public static boolean hasSecp256k1Curve() { - // For now we just check if the java version is at least 8 - String[] version = System.getProperty("java.version").split("\\."); - int major = Integer.parseInt(version[0]); - int minor = Integer.parseInt(version[1]); - return ((major > 1) || ((major > 0) && (minor > 7))); - } - - public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } - - public static synchronized void doSetup() { - if (bouncyCastleProvider == null) { - bouncyCastleProvider = new BouncyCastleProvider(); - // Make bouncycastle our default provider if we're running on a JVM version < 8 - // (earlier version don't support the EC curve we use for signatures) - if (!hasSecp256k1Curve() && !loadedBouncyCastle) { - loadedBouncyCastle = true; - Security.insertProviderAt(bouncyCastleProvider, 1); - logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve"); - } - } - } - - public GlobalCryptoSetup() { doSetup(); } -} +package meerkat.crypto.concrete; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.Provider; +import java.security.Security; + +/** + * A class that performs required crypto setup + */ +public class GlobalCryptoSetup { + final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); + + static boolean loadedBouncyCastle = false; + static Provider bouncyCastleProvider; + + public static boolean hasSecp256k1Curve() { + // For now we just check if the java version is at least 8 + String[] version = System.getProperty("java.version").split("\\."); + int major = Integer.parseInt(version[0]); + int minor = Integer.parseInt(version[1]); + return ((major > 1) || ((major > 0) && (minor > 7))); + } + + public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } + + public static synchronized void doSetup() { + if (bouncyCastleProvider == null) { + bouncyCastleProvider = new BouncyCastleProvider(); + // Make bouncycastle our default provider if we're running on a JVM version < 8 + // (earlier version don't support the EC curve we use for signatures) + if (!hasSecp256k1Curve() && !loadedBouncyCastle) { + loadedBouncyCastle = true; + Security.insertProviderAt(bouncyCastleProvider, 1); + logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve"); + } + } + } + + public GlobalCryptoSetup() { doSetup(); } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index 4f60af3..784da82 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -1,96 +1,96 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; -import meerkat.crypto.Digest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * Created by talm on 11/9/15. - */ -public class SHA256Digest extends GlobalCryptoSetup implements Digest { - final Logger logger = LoggerFactory.getLogger(getClass()); - public static final String SHA256 = "SHA-256"; - - MessageDigest hash; - - /** - * Used to convert length to bytes in proper order. - */ - ByteBuffer lenBuf = ByteBuffer.allocate(4); - - /** - * Instantiate with a specified algorithm. - * @param algorithm - * @throws NoSuchAlgorithmException - */ - public SHA256Digest(String algorithm) throws NoSuchAlgorithmException { - hash = MessageDigest.getInstance(algorithm); - } - - /** - * Instantiate with the default (SHA-256) algorithm - */ - public SHA256Digest() { this(true); } - - - /**SHA - * Instantiate with the default (SHA-256) algorithm, - * or create an empty class (for cloning) - */ - private SHA256Digest(boolean initHash) { - if (initHash) { - try { - hash = MessageDigest.getInstance(SHA256); - } catch (NoSuchAlgorithmException e) { - // Should never happen! - logger.error("Couldn't find default {} algorhtm: {}", SHA256, e); - assert false; - } - } - } - - @Override - public byte[] digest() { - return hash.digest(); - } - - @Override - public void update(Message msg) { - - lenBuf.clear(); - lenBuf.putInt(msg.getSerializedSize()); - lenBuf.flip(); - hash.update(lenBuf); - hash.update(msg.toByteString().asReadOnlyByteBuffer()); - } - - final public void update(ByteString msg) { - hash.update(msg.asReadOnlyByteBuffer()); - } - - final public void update(byte[] msg) { - hash.update(msg); - } - - final public void update(ByteBuffer msg) { - hash.update(msg); - } - - @Override - public void reset() { - hash.reset(); - } - - @Override - public SHA256Digest clone() throws CloneNotSupportedException { - SHA256Digest copy = new SHA256Digest(false); - copy.hash = (MessageDigest) hash.clone(); - return copy; - } -} +package meerkat.crypto.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.crypto.Digest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Created by talm on 11/9/15. + */ +public class SHA256Digest extends GlobalCryptoSetup implements Digest { + final Logger logger = LoggerFactory.getLogger(getClass()); + public static final String SHA256 = "SHA-256"; + + MessageDigest hash; + + /** + * Used to convert length to bytes in proper order. + */ + ByteBuffer lenBuf = ByteBuffer.allocate(4); + + /** + * Instantiate with a specified algorithm. + * @param algorithm + * @throws NoSuchAlgorithmException + */ + public SHA256Digest(String algorithm) throws NoSuchAlgorithmException { + hash = MessageDigest.getInstance(algorithm); + } + + /** + * Instantiate with the default (SHA-256) algorithm + */ + public SHA256Digest() { this(true); } + + + /**SHA + * Instantiate with the default (SHA-256) algorithm, + * or create an empty class (for cloning) + */ + private SHA256Digest(boolean initHash) { + if (initHash) { + try { + hash = MessageDigest.getInstance(SHA256); + } catch (NoSuchAlgorithmException e) { + // Should never happen! + logger.error("Couldn't find default {} algorhtm: {}", SHA256, e); + assert false; + } + } + } + + @Override + public byte[] digest() { + return hash.digest(); + } + + @Override + public void update(Message msg) { + + lenBuf.clear(); + lenBuf.putInt(msg.getSerializedSize()); + lenBuf.flip(); + hash.update(lenBuf); + hash.update(msg.toByteString().asReadOnlyByteBuffer()); + } + + final public void update(ByteString msg) { + hash.update(msg.asReadOnlyByteBuffer()); + } + + final public void update(byte[] msg) { + hash.update(msg); + } + + final public void update(ByteBuffer msg) { + hash.update(msg); + } + + @Override + public void reset() { + hash.reset(); + } + + @Override + public SHA256Digest clone() throws CloneNotSupportedException { + SHA256Digest copy = new SHA256Digest(false); + copy.hash = (MessageDigest) hash.clone(); + return copy; + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index 1113bfd..438cb51 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -1,18 +1,18 @@ -package meerkat.crypto.mixnet; - -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -/** - * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. - */ -public interface Mix2ZeroKnowledgeProver { - public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - boolean switched, - Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2); - -} +package meerkat.crypto.mixnet; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. + */ +public interface Mix2ZeroKnowledgeProver { + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean switched, + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2); + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java index dd3c251..7fa845c 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java @@ -1,23 +1,23 @@ -package meerkat.crypto.mixnet; - -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -/** - * Verify the two-ciphertext mix proof - */ -public interface Mix2ZeroKnowledgeVerifier { - /** - * Return true iff the proof is valid. - * @param in1 - * @param in2 - * @param out1 - * @param out2 - * @return - */ - boolean verify(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof); -} +package meerkat.crypto.mixnet; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Verify the two-ciphertext mix proof + */ +public interface Mix2ZeroKnowledgeVerifier { + /** + * Return true iff the proof is valid. + * @param in1 + * @param in2 + * @param out1 + * @param out2 + * @return + */ + boolean verify(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + Mixing.ZeroKnowledgeProof proof); +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 52e8844..0be60c3 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -1,11 +1,11 @@ -package meerkat.crypto.mixnet; - -import java.util.List; -import static meerkat.protobuf.Voting.*; - -/** - * Created by talm on 25/10/15. - */ -public interface Mixer { - public List mix(List ballots); -} +package meerkat.crypto.mixnet; + +import java.util.List; +import static meerkat.protobuf.Voting.*; + +/** + * Created by talm on 25/10/15. + */ +public interface Mixer { + public List mix(List ballots); +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java index e8044cd..a131a65 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java @@ -1,7 +1,7 @@ -package meerkat.crypto.mixnet; - -/** - * Created by talm on 25/10/15. - */ -public class Trustee { -} +package meerkat.crypto.mixnet; + +/** + * Created by talm on 25/10/15. + */ +public class Trustee { +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java index b733317..809678e 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java @@ -1,7 +1,7 @@ -package meerkat.crypto.mixnet; - -/** - * Created by talm on 25/10/15. - */ -public class Verifier { -} +package meerkat.crypto.mixnet; + +/** + * Created by talm on 25/10/15. + */ +public class Verifier { +} diff --git a/meerkat-common/src/main/java/meerkat/logging/LogVerifier.java b/meerkat-common/src/main/java/meerkat/logging/LogVerifier.java index 7ba928a..f27f740 100644 --- a/meerkat-common/src/main/java/meerkat/logging/LogVerifier.java +++ b/meerkat-common/src/main/java/meerkat/logging/LogVerifier.java @@ -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 { +} diff --git a/meerkat-common/src/main/java/meerkat/logging/Logger.java b/meerkat-common/src/main/java/meerkat/logging/Logger.java index 343ff31..26ec424 100644 --- a/meerkat-common/src/main/java/meerkat/logging/Logger.java +++ b/meerkat-common/src/main/java/meerkat/logging/Logger.java @@ -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 { +} diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java index 77a6663..653f130 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java @@ -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 { - - /** - * 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 msg1Sigs = msg1.getSigList(); - List 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 { + + /** + * 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 msg1Sigs = msg1.getSigList(); + List 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; + } +} diff --git a/meerkat-common/src/main/java/meerkat/util/Hex.java b/meerkat-common/src/main/java/meerkat/util/Hex.java index 2d0e4ef..8064d7d 100644 --- a/meerkat-common/src/main/java/meerkat/util/Hex.java +++ b/meerkat-common/src/main/java/meerkat/util/Hex.java @@ -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)); + } +} + diff --git a/meerkat-common/src/main/java/meerkat/voting/VotingBooth.java b/meerkat-common/src/main/java/meerkat/voting/VotingBooth.java index e337a83..5f8a7cf 100644 --- a/meerkat-common/src/main/java/meerkat/voting/VotingBooth.java +++ b/meerkat-common/src/main/java/meerkat/voting/VotingBooth.java @@ -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); +} diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 0fe35f8..e25b2d3 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -1,80 +1,80 @@ -syntax = "proto3"; - -package meerkat; - -option java_package = "meerkat.protobuf"; - -import 'meerkat/crypto.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 - repeated string tag = 1; - - // The actual content of the message - bytes data = 2; -} - -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) - SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer) - TAG = 4; // Find all entries in database that have a specific tag - - // 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 = 5; // 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; - } -} - -message MessageFilterList { - - // Combination of filters. - // To be implemented using intersection ("AND") operations. - repeated MessageFilter filter = 1; - +syntax = "proto3"; + +package meerkat; + +option java_package = "meerkat.protobuf"; + +import 'meerkat/crypto.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 + repeated string tag = 1; + + // The actual content of the message + bytes data = 2; +} + +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) + SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer) + TAG = 4; // Find all entries in database that have a specific tag + + // 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 = 5; // 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; + } +} + +message MessageFilterList { + + // Combination of filters. + // To be implemented using intersection ("AND") operations. + repeated MessageFilter filter = 1; + } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto index a13c8a7..81072e9 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -1,48 +1,48 @@ -syntax = "proto3"; - -package meerkat; - -option java_package = "meerkat.protobuf"; - -message Mail{ - enum Type { - SECRET = 0; - COMMITMENT = 1; - COMPLAINT = 2; - DONE = 3; - ANSWER = 4; - YCOMMITMENT = 5; - YCOMPLAINT = 6; - YANSWER = 7; - ABORT = 8; - } - int32 sender = 1; - int32 destination = 2; - bool isPrivate = 3; - Type type = 4; - bytes message = 5; -} - -message SecretMessage { - int32 i = 1; - int32 j = 2; - bytes secret = 3; -} - -message DoubleSecretMessage{ - int32 i = 1; - int32 j = 2; - bytes secret = 3; - bytes secretT = 4; -} - -message CommitmentMessage{ - int32 k = 1; - bytes commitment = 2; -} - -message EmptyMessage{} - -message IDMessage{ - int32 id = 1; -} +syntax = "proto3"; + +package meerkat; + +option java_package = "meerkat.protobuf"; + +message Mail{ + enum Type { + SECRET = 0; + COMMITMENT = 1; + COMPLAINT = 2; + DONE = 3; + ANSWER = 4; + YCOMMITMENT = 5; + YCOMPLAINT = 6; + YANSWER = 7; + ABORT = 8; + } + int32 sender = 1; + int32 destination = 2; + bool isPrivate = 3; + Type type = 4; + bytes message = 5; +} + +message SecretMessage { + int32 i = 1; + int32 j = 2; + bytes secret = 3; +} + +message DoubleSecretMessage{ + int32 i = 1; + int32 j = 2; + bytes secret = 3; + bytes secretT = 4; +} + +message CommitmentMessage{ + int32 k = 1; + bytes commitment = 2; +} + +message EmptyMessage{} + +message IDMessage{ + int32 id = 1; +} diff --git a/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto index d8c40d3..9f1f818 100644 --- a/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto +++ b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto @@ -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 } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/crypto.proto b/meerkat-common/src/main/proto/meerkat/crypto.proto index eeec159..3b3e906 100644 --- a/meerkat-common/src/main/proto/meerkat/crypto.proto +++ b/meerkat-common/src/main/proto/meerkat/crypto.proto @@ -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; +} + diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 50cffc7..2d5d6da 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -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; } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 9837cce..f539ab8 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -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; +} diff --git a/meerkat-common/src/main/resources/logback.groovy b/meerkat-common/src/main/resources/logback.groovy index 076b6c4..85fa80d 100644 --- a/meerkat-common/src/main/resources/logback.groovy +++ b/meerkat-common/src/main/resources/logback.groovy @@ -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) + + diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java index cc41497..cefc1b2 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java @@ -1,50 +1,50 @@ -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; - -import java.math.BigInteger; -import static org.junit.Assert.*; - -/** - * Created by talm on 12/11/15. - */ -public class ECDSADeterministicSignatureTest extends ECDSASignatureTest { - - @Override - protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); } - - - /** - * Make sure signatures don't vary - */ - @Test - public void testDeterministicSigning() throws Exception { - loadSigningKeys(); - - - for (int i = 0; i < REPEAT_COUNT; ++i) { - BigInteger rawMsg = new BigInteger(50, rand); - Message msg = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; - - signer.updateContent(msg); - sigs[0] = signer.sign(); - byte[] canonicalSig = sigs[0].toByteArray(); - - for (int j = 1; j < sigs.length; ++j) { - signer.updateContent(msg); - sigs[j] = signer.sign(); - - byte[] newSig = sigs[j].toByteArray(); - - assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig); - } - } - } -} +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; + +import java.math.BigInteger; +import static org.junit.Assert.*; + +/** + * Created by talm on 12/11/15. + */ +public class ECDSADeterministicSignatureTest extends ECDSASignatureTest { + + @Override + protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); } + + + /** + * Make sure signatures don't vary + */ + @Test + public void testDeterministicSigning() throws Exception { + loadSigningKeys(); + + + for (int i = 0; i < REPEAT_COUNT; ++i) { + BigInteger rawMsg = new BigInteger(50, rand); + Message msg = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; + + signer.updateContent(msg); + sigs[0] = signer.sign(); + byte[] canonicalSig = sigs[0].toByteArray(); + + for (int j = 1; j < sigs.length; ++j) { + signer.updateContent(msg); + sigs[j] = signer.sign(); + + byte[] newSig = sigs[j].toByteArray(); + + assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig); + } + } + } +} diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java index 37c2d1b..327292a 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java @@ -1,220 +1,220 @@ -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; - -import java.io.InputStream; -import java.math.BigInteger; -import java.security.KeyStore; -import java.util.Random; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Created by talm on 12/11/15. - */ -public class ECDSASignatureTest { - public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; - public static String KEYFILE_PASSWORD = "secret"; - - public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; - public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der"; - - public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt"; - public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig"; - - public static String HELLO_WORLD = "hello world!"; - - public final static int REPEAT_COUNT = 10; - - Random rand = new Random(0); - - protected ECDSASignature signer; - - protected ECDSASignature getSigner() { return new ECDSASignature(); } - - @Before - public void setup() throws Exception { - signer = getSigner(); - } - - @Test - public void loadSignatureKey() throws Exception { - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD.toCharArray(); - - KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); - signer.loadSigningCertificate(keyStore); - keyStream.close(); - } - - @Test - public void loadPEMVerificationKey() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - } - - @Test - public void loadDERVerificationKey() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - } - - - @Test - public void verifyValidSig() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - sig.setData(ByteString.readFrom(sigStream)); - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertTrue("Signature did not verify!", signer.verify()); - } - - @Test - public void verifyInvalidSig() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - byte[] sigData = ByteString.readFrom(sigStream).toByteArray(); - ++sigData[0]; - - sig.setData(ByteString.copyFrom(sigData)); - - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertFalse("Bad Signature passed verification!", signer.verify()); - } - - - @Test - public void verifyInvalidMsg() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - sig.setData(ByteString.readFrom(sigStream)); - byte[] msgData = ByteString.readFrom(msgStream).toByteArray(); - ++msgData[0]; - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertFalse("Signature doesn't match message but passed verification!", signer.verify()); - } - - - - protected void loadSigningKeys() throws Exception { - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD.toCharArray(); - - KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); - signer.loadSigningCertificate(keyStore); - } - - @Test - public void signAndVerify() throws Exception { - loadSigningKeys(); - - BigInteger rawMsg = new BigInteger(50, rand); - Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - - signer.updateContent(usMsg); - Crypto.Signature sig = signer.sign(); - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - signer.initVerify(sig); - signer.updateContent(usMsg); - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - - @Test - public void signMultipleAndVerify() throws Exception { - loadSigningKeys(); - - Message[] msgs = new Message[REPEAT_COUNT]; - for (int i = 0; i < msgs.length; ++i) { - - BigInteger rawMsg = new BigInteger(50, rand); - msgs[i] = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - signer.updateContent(msgs[i]); - } - - Crypto.Signature sig = signer.sign(); - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - signer.initVerify(sig); - for (int i = 0; i < msgs.length; ++i) { - signer.updateContent(msgs[i]); - } - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - @Test - public void multipleSignAndVerify() throws Exception { - loadSigningKeys(); - - Message[] msgs = new Message[REPEAT_COUNT]; - Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; - for (int i = 0; i < msgs.length; ++i) { - BigInteger rawMsg = new BigInteger(50, rand); - msgs[i] = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - signer.updateContent(msgs[i]); - sigs[i] = signer.sign(); - } - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - - for (int i = 0; i < msgs.length; ++i) { - signer.initVerify(sigs[i]); - signer.updateContent(msgs[i]); - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - } - - - -} +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; + +import java.io.InputStream; +import java.math.BigInteger; +import java.security.KeyStore; +import java.util.Random; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Created by talm on 12/11/15. + */ +public class ECDSASignatureTest { + public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + public static String KEYFILE_PASSWORD = "secret"; + + public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der"; + + public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt"; + public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig"; + + public static String HELLO_WORLD = "hello world!"; + + public final static int REPEAT_COUNT = 10; + + Random rand = new Random(0); + + protected ECDSASignature signer; + + protected ECDSASignature getSigner() { return new ECDSASignature(); } + + @Before + public void setup() throws Exception { + signer = getSigner(); + } + + @Test + public void loadSignatureKey() throws Exception { + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD.toCharArray(); + + KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); + signer.loadSigningCertificate(keyStore); + keyStream.close(); + } + + @Test + public void loadPEMVerificationKey() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + } + + @Test + public void loadDERVerificationKey() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + } + + + @Test + public void verifyValidSig() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + sig.setData(ByteString.readFrom(sigStream)); + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertTrue("Signature did not verify!", signer.verify()); + } + + @Test + public void verifyInvalidSig() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + byte[] sigData = ByteString.readFrom(sigStream).toByteArray(); + ++sigData[0]; + + sig.setData(ByteString.copyFrom(sigData)); + + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertFalse("Bad Signature passed verification!", signer.verify()); + } + + + @Test + public void verifyInvalidMsg() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + sig.setData(ByteString.readFrom(sigStream)); + byte[] msgData = ByteString.readFrom(msgStream).toByteArray(); + ++msgData[0]; + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertFalse("Signature doesn't match message but passed verification!", signer.verify()); + } + + + + protected void loadSigningKeys() throws Exception { + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD.toCharArray(); + + KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); + signer.loadSigningCertificate(keyStore); + } + + @Test + public void signAndVerify() throws Exception { + loadSigningKeys(); + + BigInteger rawMsg = new BigInteger(50, rand); + Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + + signer.updateContent(usMsg); + Crypto.Signature sig = signer.sign(); + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + signer.initVerify(sig); + signer.updateContent(usMsg); + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + + @Test + public void signMultipleAndVerify() throws Exception { + loadSigningKeys(); + + Message[] msgs = new Message[REPEAT_COUNT]; + for (int i = 0; i < msgs.length; ++i) { + + BigInteger rawMsg = new BigInteger(50, rand); + msgs[i] = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + signer.updateContent(msgs[i]); + } + + Crypto.Signature sig = signer.sign(); + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + signer.initVerify(sig); + for (int i = 0; i < msgs.length; ++i) { + signer.updateContent(msgs[i]); + } + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + @Test + public void multipleSignAndVerify() throws Exception { + loadSigningKeys(); + + Message[] msgs = new Message[REPEAT_COUNT]; + Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; + for (int i = 0; i < msgs.length; ++i) { + BigInteger rawMsg = new BigInteger(50, rand); + msgs[i] = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + signer.updateContent(msgs[i]); + sigs[i] = signer.sign(); + } + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + + for (int i = 0; i < msgs.length; ++i) { + signer.initVerify(sigs[i]); + signer.updateContent(msgs[i]); + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + } + + + +} diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java index 81375e0..a911b96 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java @@ -1,122 +1,122 @@ -package meerkat.crypto.concrete; - -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Voting; -import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.util.Pair; - -import java.math.BigInteger; -import java.util.Random; - -import static org.junit.Assert.*; - -/** - * Test class for {@link ECElGamalEncryption} - */ -public class ECElGamalEncryptionTest { - final Logger logger = LoggerFactory.getLogger(getClass()); - /** - * Number of times to repeat probabilistic tests. - */ - public final static int CONFIDENCE = 10; - - Random rand = new Random(0); // Insecure deterministic random for testing. - - ECElGamal.SK key; - ECGroup group; - ECElGamalEncryption enc; - ConcreteCrypto.ElGamalPublicKey serializedPk; - - - @Before - public void setup() throws Exception { - group = new ECGroup("secp256k1"); - BigInteger sk = ECElGamal.generateSecretKey(group, rand); - key = new ECElGamal.SK(group, sk); - serializedPk = ECElGamalUtils.serializePk(group, key); - - - enc = new ECElGamalEncryption(); - - enc.init(serializedPk); - } - - - Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { - Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); - ballot.setSerialNumber(rand.nextInt(1000000)); - for (int i = 0; i < numQuestions; ++i) { - Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); - for (int j = 0; j < numAnswers; ++j) { - answers.addAnswer(rand.nextInt(maxAnswer)); - } - } - return ballot.build(); - } - - /** - * Testing just the key management - * @throws Exception - */ - @Test - public void testPkSerialization() throws Exception { - ECElGamal.PK pk = enc.getElGamalPK(); - - ECPoint point = enc.getGroup().sample(rand); - Pair cipher = pk.encrypt(point, pk.getRandom(rand)); - - ECPoint decrypted = key.decrypt(cipher); - - assertEquals("Decrypted value not equal to encrypted value!", point, decrypted); - } - - @Test - public void testEncryption() throws Exception { - for (int i = 0; i < CONFIDENCE; ++i) { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) { - logger.error("Test Message too big (|msg|={} > max={}), expect failure.", - msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength()); - } - - Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand)); - - Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText); - - assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted); - } - } - - @Test - public void testRerandomizeModifiesCiphertext() throws Exception { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand)); - Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand)); - assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2); - } - - @Test - public void testRerandomizePreservesPlaintext() throws Exception { - for (int i = 0; i < CONFIDENCE; ++i) { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - - Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand)); - Crypto.RerandomizableEncryptedMessage cipher2 = cipher; - for (int j = 0; j < CONFIDENCE; ++j) - cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand)); - - Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, - cipher2); - - assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted); - } - } -} - +package meerkat.crypto.concrete; + +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.util.Pair; + +import java.math.BigInteger; +import java.util.Random; + +import static org.junit.Assert.*; + +/** + * Test class for {@link ECElGamalEncryption} + */ +public class ECElGamalEncryptionTest { + final Logger logger = LoggerFactory.getLogger(getClass()); + /** + * Number of times to repeat probabilistic tests. + */ + public final static int CONFIDENCE = 10; + + Random rand = new Random(0); // Insecure deterministic random for testing. + + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + + + @Before + public void setup() throws Exception { + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = ECElGamalUtils.serializePk(group, key); + + + enc = new ECElGamalEncryption(); + + enc.init(serializedPk); + } + + + Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { + Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); + ballot.setSerialNumber(rand.nextInt(1000000)); + for (int i = 0; i < numQuestions; ++i) { + Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); + for (int j = 0; j < numAnswers; ++j) { + answers.addAnswer(rand.nextInt(maxAnswer)); + } + } + return ballot.build(); + } + + /** + * Testing just the key management + * @throws Exception + */ + @Test + public void testPkSerialization() throws Exception { + ECElGamal.PK pk = enc.getElGamalPK(); + + ECPoint point = enc.getGroup().sample(rand); + Pair cipher = pk.encrypt(point, pk.getRandom(rand)); + + ECPoint decrypted = key.decrypt(cipher); + + assertEquals("Decrypted value not equal to encrypted value!", point, decrypted); + } + + @Test + public void testEncryption() throws Exception { + for (int i = 0; i < CONFIDENCE; ++i) { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) { + logger.error("Test Message too big (|msg|={} > max={}), expect failure.", + msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength()); + } + + Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand)); + + Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText); + + assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted); + } + } + + @Test + public void testRerandomizeModifiesCiphertext() throws Exception { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand)); + assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2); + } + + @Test + public void testRerandomizePreservesPlaintext() throws Exception { + for (int i = 0; i < CONFIDENCE; ++i) { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + + Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage cipher2 = cipher; + for (int j = 0; j < CONFIDENCE; ++j) + cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand)); + + Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, + cipher2); + + assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted); + } + } +} + diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java index 66e1647..f83aaea 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java @@ -1,89 +1,89 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.GeneratedMessage; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECPoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.primitives.generic.ElGamal; -import org.factcenter.qilin.util.Pair; - -import java.io.ByteArrayInputStream; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; - -/** - * utilities for ECElgamal - */ -public class ECElGamalUtils { - final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); - - public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; - - /** - * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} - * @param pk - * @return - */ - public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { - ECPoint pkPoint = pk.getPK(); - ECParameterSpec params = group.getCurveParams(); - - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); - - try { - KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); - PublicKey javaPk = fact.generatePublic(pubKeySpec); - ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() - .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); - - return serializedPk; - } catch (NoSuchAlgorithmException|InvalidKeySpecException e) { - logger.error("Should never happen!", e); - throw new RuntimeException("Error converting public key!", e); - } - } - - /** - * Standard (non-threshold) decryption for testing purposes. - * @param secretKey - * @return - */ - public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) - throws InvalidProtocolBufferException { - ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); - ByteString c1encoded = cipherText.getC1(); - ByteString c2encoded = cipherText.getC2(); - - ECPoint c1 = group.decode(c1encoded.toByteArray()); - ECPoint c2 = group.decode(c2encoded.toByteArray()); - - ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); - - byte[] plaintext = group.injectiveDecode(plaintextEncoded); - - ByteArrayInputStream in = new ByteArrayInputStream(plaintext); - - try { - java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); - builder.mergeDelimitedFrom(in); - return plaintextMessageType.cast(builder.build()); - } catch (Exception e) { - logger.error("Error parsing incoming message", e); - throw new InvalidProtocolBufferException("Plaintext protobuf error"); - } - } - -} +package meerkat.crypto.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.generic.ElGamal; +import org.factcenter.qilin.util.Pair; + +import java.io.ByteArrayInputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; + +/** + * utilities for ECElgamal + */ +public class ECElGamalUtils { + final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (NoSuchAlgorithmException|InvalidKeySpecException e) { + logger.error("Should never happen!", e); + throw new RuntimeException("Error converting public key!", e); + } + } + + /** + * Standard (non-threshold) decryption for testing purposes. + * @param secretKey + * @return + */ + public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) + throws InvalidProtocolBufferException { + ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); + ByteString c1encoded = cipherText.getC1(); + ByteString c2encoded = cipherText.getC2(); + + ECPoint c1 = group.decode(c1encoded.toByteArray()); + ECPoint c2 = group.decode(c2encoded.toByteArray()); + + ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); + + byte[] plaintext = group.injectiveDecode(plaintextEncoded); + + ByteArrayInputStream in = new ByteArrayInputStream(plaintext); + + try { + java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); + builder.mergeDelimitedFrom(in); + return plaintextMessageType.cast(builder.build()); + } catch (Exception e) { + logger.error("Error parsing incoming message", e); + throw new InvalidProtocolBufferException("Plaintext protobuf error"); + } + } + +} diff --git a/meerkat-common/src/test/resources/certs/README.md b/meerkat-common/src/test/resources/certs/README.md index f7283d9..ecb74d0 100644 --- a/meerkat-common/src/test/resources/certs/README.md +++ b/meerkat-common/src/test/resources/certs/README.md @@ -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 diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user1-key-with-password-secret.pem b/meerkat-common/src/test/resources/certs/enduser-certs/user1-key-with-password-secret.pem index e859995..dccf58d 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user1-key-with-password-secret.pem +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user1-key-with-password-secret.pem @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user1-key.pem b/meerkat-common/src/test/resources/certs/enduser-certs/user1-key.pem index 6619e37..239bd21 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user1-key.pem +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user1-key.pem @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user1-pubkey.pem b/meerkat-common/src/test/resources/certs/enduser-certs/user1-pubkey.pem index 1c0a0c1..4724631 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user1-pubkey.pem +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user1-pubkey.pem @@ -1,4 +1,4 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugbDZEWPbbJWroKTiTmqCl+Lgc+ -EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+vRxZoV0YbDNNOQ== ------END PUBLIC KEY----- +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugbDZEWPbbJWroKTiTmqCl+Lgc+ +EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+vRxZoV0YbDNNOQ== +-----END PUBLIC KEY----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user1.crt b/meerkat-common/src/test/resources/certs/enduser-certs/user1.crt index d80093f..e3d4843 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user1.crt +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user1.crt @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user1.csr b/meerkat-common/src/test/resources/certs/enduser-certs/user1.csr index 20e1efc..0f59d09 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user1.csr +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user1.csr @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user2-key.pem b/meerkat-common/src/test/resources/certs/enduser-certs/user2-key.pem index 2d31bb8..1967905 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user2-key.pem +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user2-key.pem @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user2-pubkey.pem b/meerkat-common/src/test/resources/certs/enduser-certs/user2-pubkey.pem index 5d86d4c..72f7acf 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user2-pubkey.pem +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user2-pubkey.pem @@ -1,4 +1,4 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsgN4XcXCwQU9zT0Bekdy4aJZi0 -TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1EonZy8kIvp1wtHw== ------END PUBLIC KEY----- +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsgN4XcXCwQU9zT0Bekdy4aJZi0 +TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1EonZy8kIvp1wtHw== +-----END PUBLIC KEY----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user2.crt b/meerkat-common/src/test/resources/certs/enduser-certs/user2.crt index a211365..e618261 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user2.crt +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user2.crt @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user2.csr b/meerkat-common/src/test/resources/certs/enduser-certs/user2.csr index bb3c2d0..774a0d3 100644 --- a/meerkat-common/src/test/resources/certs/enduser-certs/user2.csr +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user2.csr @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/1000.pem b/meerkat-common/src/test/resources/certs/intermediate-ca-1/1000.pem index d80093f..e3d4843 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/1000.pem +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/1000.pem @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/1001.pem b/meerkat-common/src/test/resources/certs/intermediate-ca-1/1001.pem index a211365..e618261 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/1001.pem +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/1001.pem @@ -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----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex index 1cd80cf..72b4dde 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex @@ -1,2 +1,2 @@ -V 251108161354Z 1000 unknown /CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting -V 251108162033Z 1001 unknown /CN=Polling Station 2/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting +V 251108161354Z 1000 unknown /CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting +V 251108162033Z 1001 unknown /CN=Polling Station 2/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr index 3a7e39e..f77ac48 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr @@ -1 +1 @@ -unique_subject = no +unique_subject = no diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr.old b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr.old index 3a7e39e..f77ac48 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr.old +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.attr.old @@ -1 +1 @@ -unique_subject = no +unique_subject = no diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.old b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.old index 7dcd55e..60f290b 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.old +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certindex.old @@ -1 +1 @@ -V 251108161354Z 1000 unknown /CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting +V 251108161354Z 1000 unknown /CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial index 7d802a3..a9b8266 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial @@ -1 +1 @@ -1002 +1002 diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial.old b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial.old index dd11724..ecc680e 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial.old +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/certserial.old @@ -1 +1 @@ -1001 +1001 diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/crlnumber b/meerkat-common/src/test/resources/certs/intermediate-ca-1/crlnumber index 83b33d2..d5b0eb5 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/crlnumber +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/crlnumber @@ -1 +1 @@ -1000 +1000 diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1-private-key.pem b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1-private-key.pem index cf0a641..5c678f2 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1-private-key.pem +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1-private-key.pem @@ -1,5 +1,5 @@ ------BEGIN PRIVATE KEY----- -MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgJvMhOfcQfdK/42QlBbri -IYXLM/gVHq/yppOykDqB3s6hRANCAAQoShAtCGW5c9pk/4/sKN1qjCgDKngqJpba -kku6cIDqXDr+aHsl+/KdSHd46OI3fEynl+/Pc85wRsaY6Z7b1PdS ------END PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgJvMhOfcQfdK/42QlBbri +IYXLM/gVHq/yppOykDqB3s6hRANCAAQoShAtCGW5c9pk/4/sKN1qjCgDKngqJpba +kku6cIDqXDr+aHsl+/KdSHd46OI3fEynl+/Pc85wRsaY6Z7b1PdS +-----END PRIVATE KEY----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.crt b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.crt index 751d8e7..dda53dc 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.crt +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.crt @@ -1,21 +1,21 @@ ------BEGIN CERTIFICATE----- -MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw -EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL -SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW -BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j -YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa -MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET -MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI -ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49 -AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o -eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW -gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI -KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy -Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90 -aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw -AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0 -MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI -zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA -skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8= ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw +EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL +SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW +BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j +YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa +MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET +MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI +ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49 +AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o +eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW +gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI +KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy +Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90 +aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw +AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0 +MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI +zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA +skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8= +-----END CERTIFICATE----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.csr b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.csr index fce3021..55f66c1 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.csr +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/intermediate-ca-1.csr @@ -1,10 +1,10 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBTTCB9QIBADCBlTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx -ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExHDAaBgNV -BAsME01lZXJrYXQgVm90aW5nIFRlYW0xKTAnBgNVBAMMIE1lZXJrYXQgVm90aW5n -IEludGVybWVkaWF0ZSBDQSAxMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKEoQLQhl -uXPaZP+P7CjdaowoAyp4KiaW2pJLunCA6lw6/mh7JfvynUh3eOjiN3xMp5fvz3PO -cEbGmOme29T3UqAAMAoGCCqGSM49BAMCA0cAMEQCIFlyJO5NFqnMUu5hOlQa872E -yy0V3zkqeN6Aly+LtEQqAiAfHwbi1lkJOZT2tOX8gfJzcac2jKmbgIhmITNq7uma -Wg== ------END CERTIFICATE REQUEST----- +-----BEGIN CERTIFICATE REQUEST----- +MIIBTTCB9QIBADCBlTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx +ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExHDAaBgNV +BAsME01lZXJrYXQgVm90aW5nIFRlYW0xKTAnBgNVBAMMIE1lZXJrYXQgVm90aW5n +IEludGVybWVkaWF0ZSBDQSAxMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKEoQLQhl +uXPaZP+P7CjdaowoAyp4KiaW2pJLunCA6lw6/mh7JfvynUh3eOjiN3xMp5fvz3PO +cEbGmOme29T3UqAAMAoGCCqGSM49BAMCA0cAMEQCIFlyJO5NFqnMUu5hOlQa872E +yy0V3zkqeN6Aly+LtEQqAiAfHwbi1lkJOZT2tOX8gfJzcac2jKmbgIhmITNq7uma +Wg== +-----END CERTIFICATE REQUEST----- diff --git a/meerkat-common/src/test/resources/certs/intermediate-ca-1/openssl-intermediate-ca.conf b/meerkat-common/src/test/resources/certs/intermediate-ca-1/openssl-intermediate-ca.conf index 090ca1a..aa44c33 100644 --- a/meerkat-common/src/test/resources/certs/intermediate-ca-1/openssl-intermediate-ca.conf +++ b/meerkat-common/src/test/resources/certs/intermediate-ca-1/openssl-intermediate-ca.conf @@ -1,46 +1,46 @@ -[ ca ] -default_ca = myca - -[ crl_ext ] -issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - - [ myca ] - dir = ./ - new_certs_dir = $dir - unique_subject = no - certificate = $dir/intermediate-ca-1.crt - database = $dir/certindex - private_key = $dir/intermediate-ca-1-private-key.pem - serial = $dir/certserial - default_days = 3650 - default_md = sha256 - policy = myca_policy - x509_extensions = myca_extensions - crlnumber = $dir/crlnumber - default_crl_days = 3650 - - [ myca_policy ] - commonName = supplied - stateOrProvinceName = optional - countryName = optional - emailAddress = optional - organizationName = supplied - organizationalUnitName = optional - - [ myca_extensions ] - basicConstraints = critical,CA:FALSE - keyUsage = critical,any - subjectKeyIdentifier = hash - authorityKeyIdentifier = keyid:always,issuer - keyUsage = digitalSignature,keyEncipherment - extendedKeyUsage = serverAuth - crlDistributionPoints = @crl_section - authorityInfoAccess = @ocsp_section - - [crl_section] - URI.0 = http://crl.factcenter.org/meerkat-intermediate1.crl - - [ocsp_section] - caIssuers;URI.0 = http://pki.factcenter.org/meerkat-intermediate-ca.crt - OCSP;URI.0 = http://ocsp.factcenter.org/ +[ ca ] +default_ca = myca + +[ crl_ext ] +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + + [ myca ] + dir = ./ + new_certs_dir = $dir + unique_subject = no + certificate = $dir/intermediate-ca-1.crt + database = $dir/certindex + private_key = $dir/intermediate-ca-1-private-key.pem + serial = $dir/certserial + default_days = 3650 + default_md = sha256 + policy = myca_policy + x509_extensions = myca_extensions + crlnumber = $dir/crlnumber + default_crl_days = 3650 + + [ myca_policy ] + commonName = supplied + stateOrProvinceName = optional + countryName = optional + emailAddress = optional + organizationName = supplied + organizationalUnitName = optional + + [ myca_extensions ] + basicConstraints = critical,CA:FALSE + keyUsage = critical,any + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always,issuer + keyUsage = digitalSignature,keyEncipherment + extendedKeyUsage = serverAuth + crlDistributionPoints = @crl_section + authorityInfoAccess = @ocsp_section + + [crl_section] + URI.0 = http://crl.factcenter.org/meerkat-intermediate1.crl + + [ocsp_section] + caIssuers;URI.0 = http://pki.factcenter.org/meerkat-intermediate-ca.crt + OCSP;URI.0 = http://ocsp.factcenter.org/ diff --git a/meerkat-common/src/test/resources/certs/root-ca/1000.pem b/meerkat-common/src/test/resources/certs/root-ca/1000.pem index 751d8e7..dda53dc 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/1000.pem +++ b/meerkat-common/src/test/resources/certs/root-ca/1000.pem @@ -1,21 +1,21 @@ ------BEGIN CERTIFICATE----- -MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw -EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL -SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW -BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j -YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa -MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET -MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI -ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49 -AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o -eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW -gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI -KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy -Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90 -aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw -AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0 -MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI -zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA -skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8= ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw +EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL +SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW +BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j +YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa +MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET +MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI +ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49 +AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o +eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW +gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI +KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy +Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90 +aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw +AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0 +MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI +zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA +skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8= +-----END CERTIFICATE----- diff --git a/meerkat-common/src/test/resources/certs/root-ca/certindex b/meerkat-common/src/test/resources/certs/root-ca/certindex index e4550ca..ec8e90d 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/certindex +++ b/meerkat-common/src/test/resources/certs/root-ca/certindex @@ -1 +1 @@ -V 251108160802Z 1000 unknown /CN=Meerkat Voting Intermediate CA 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting Team +V 251108160802Z 1000 unknown /CN=Meerkat Voting Intermediate CA 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting Team diff --git a/meerkat-common/src/test/resources/certs/root-ca/certindex.attr b/meerkat-common/src/test/resources/certs/root-ca/certindex.attr index 3a7e39e..f77ac48 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/certindex.attr +++ b/meerkat-common/src/test/resources/certs/root-ca/certindex.attr @@ -1 +1 @@ -unique_subject = no +unique_subject = no diff --git a/meerkat-common/src/test/resources/certs/root-ca/certserial b/meerkat-common/src/test/resources/certs/root-ca/certserial index dd11724..ecc680e 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/certserial +++ b/meerkat-common/src/test/resources/certs/root-ca/certserial @@ -1 +1 @@ -1001 +1001 diff --git a/meerkat-common/src/test/resources/certs/root-ca/certserial.old b/meerkat-common/src/test/resources/certs/root-ca/certserial.old index 83b33d2..d5b0eb5 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/certserial.old +++ b/meerkat-common/src/test/resources/certs/root-ca/certserial.old @@ -1 +1 @@ -1000 +1000 diff --git a/meerkat-common/src/test/resources/certs/root-ca/crlnumber b/meerkat-common/src/test/resources/certs/root-ca/crlnumber index 83b33d2..d5b0eb5 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/crlnumber +++ b/meerkat-common/src/test/resources/certs/root-ca/crlnumber @@ -1 +1 @@ -1000 +1000 diff --git a/meerkat-common/src/test/resources/certs/root-ca/openssl-ca.conf b/meerkat-common/src/test/resources/certs/root-ca/openssl-ca.conf index 39e8b00..e94692e 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/openssl-ca.conf +++ b/meerkat-common/src/test/resources/certs/root-ca/openssl-ca.conf @@ -1,61 +1,61 @@ -[ ca ] -default_ca = myca - -[ crl_ext ] -issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - - [ myca ] - dir = ./ - new_certs_dir = $dir - unique_subject = no - certificate = $dir/root-ca.crt - database = $dir/certindex - private_key = $dir/root-ca-private-key.pem - serial = $dir/certserial - default_days = 3650 - default_md = sha256 - policy = myca_policy - x509_extensions = myca_extensions - crlnumber = $dir/crlnumber - default_crl_days = 3650 - - [ myca_policy ] - commonName = supplied - stateOrProvinceName = optional - countryName = optional - emailAddress = optional - organizationName = supplied - organizationalUnitName = optional - - [ myca_extensions ] - basicConstraints = critical,CA:TRUE - keyUsage = critical,any - subjectKeyIdentifier = hash - authorityKeyIdentifier = keyid:always,issuer - keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign - extendedKeyUsage = serverAuth - crlDistributionPoints = @crl_section - subjectAltName = @alt_names - authorityInfoAccess = @ocsp_section - - [ v3_ca ] - basicConstraints = critical,CA:TRUE,pathlen:0 - keyUsage = critical,any - subjectKeyIdentifier = hash - authorityKeyIdentifier = keyid:always,issuer - keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign - extendedKeyUsage = serverAuth - crlDistributionPoints = @crl_section - subjectAltName = @alt_names - authorityInfoAccess = @ocsp_section - - [alt_names] - DNS.0 = Meerkat Voting Intermediate CA 1 - - [crl_section] - URI.0 = http://crl.factcenter.org/meerkat-root-ca.crl - - [ocsp_section] - caIssuers;URI.0 = http://pki.factcenter.org/meerkat-root-ca.crt - OCSP;URI.0 = http://ocsp.factcenter.org/ +[ ca ] +default_ca = myca + +[ crl_ext ] +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + + [ myca ] + dir = ./ + new_certs_dir = $dir + unique_subject = no + certificate = $dir/root-ca.crt + database = $dir/certindex + private_key = $dir/root-ca-private-key.pem + serial = $dir/certserial + default_days = 3650 + default_md = sha256 + policy = myca_policy + x509_extensions = myca_extensions + crlnumber = $dir/crlnumber + default_crl_days = 3650 + + [ myca_policy ] + commonName = supplied + stateOrProvinceName = optional + countryName = optional + emailAddress = optional + organizationName = supplied + organizationalUnitName = optional + + [ myca_extensions ] + basicConstraints = critical,CA:TRUE + keyUsage = critical,any + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always,issuer + keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign + extendedKeyUsage = serverAuth + crlDistributionPoints = @crl_section + subjectAltName = @alt_names + authorityInfoAccess = @ocsp_section + + [ v3_ca ] + basicConstraints = critical,CA:TRUE,pathlen:0 + keyUsage = critical,any + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always,issuer + keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign + extendedKeyUsage = serverAuth + crlDistributionPoints = @crl_section + subjectAltName = @alt_names + authorityInfoAccess = @ocsp_section + + [alt_names] + DNS.0 = Meerkat Voting Intermediate CA 1 + + [crl_section] + URI.0 = http://crl.factcenter.org/meerkat-root-ca.crl + + [ocsp_section] + caIssuers;URI.0 = http://pki.factcenter.org/meerkat-root-ca.crt + OCSP;URI.0 = http://ocsp.factcenter.org/ diff --git a/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key-with-password-secret.pem b/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key-with-password-secret.pem index a0c442d..2801557 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key-with-password-secret.pem +++ b/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key-with-password-secret.pem @@ -1,8 +1,8 @@ ------BEGIN EC PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-256-CBC,B8CA131346FD6C9568A6C80935F2AF14 - -8q1seEln39/tQTo5KqN+qNRhd0fQ0oC71dYpfTHsP0NlNmjMtwKo2niFwzjxnSyP -vpJjGzUlnq30ucbeJA7CDm/1cmYAU5gGQ7gldgpi2TQVS+EBjqi/Y5P9AlrgLv6K -tKe4AvkqQcpi4ZvlUL9xmNaM9jEH4syopR9YClEMfa8= ------END EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,B8CA131346FD6C9568A6C80935F2AF14 + +8q1seEln39/tQTo5KqN+qNRhd0fQ0oC71dYpfTHsP0NlNmjMtwKo2niFwzjxnSyP +vpJjGzUlnq30ucbeJA7CDm/1cmYAU5gGQ7gldgpi2TQVS+EBjqi/Y5P9AlrgLv6K +tKe4AvkqQcpi4ZvlUL9xmNaM9jEH4syopR9YClEMfa8= +-----END EC PRIVATE KEY----- diff --git a/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key.pem b/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key.pem index 7966a28..7176b2a 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key.pem +++ b/meerkat-common/src/test/resources/certs/root-ca/root-ca-private-key.pem @@ -1,5 +1,5 @@ ------BEGIN EC PRIVATE KEY----- -MHQCAQEEIEi9y6pSKu1kDZcIfQQAnojl1iFxm32W0DVCp2P6HRrkoAcGBSuBBAAK -oUQDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+zFgFwvWHoWf6yJsSB -ymviB5yUaH+cE+/3LXlGbpRzYKLBYQ== ------END EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIEi9y6pSKu1kDZcIfQQAnojl1iFxm32W0DVCp2P6HRrkoAcGBSuBBAAK +oUQDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+zFgFwvWHoWf6yJsSB +ymviB5yUaH+cE+/3LXlGbpRzYKLBYQ== +-----END EC PRIVATE KEY----- diff --git a/meerkat-common/src/test/resources/certs/root-ca/root-ca.crt b/meerkat-common/src/test/resources/certs/root-ca/root-ca.crt index d0bd1fa..e884528 100644 --- a/meerkat-common/src/test/resources/certs/root-ca/root-ca.crt +++ b/meerkat-common/src/test/resources/certs/root-ca/root-ca.crt @@ -1,17 +1,17 @@ ------BEGIN CERTIFICATE----- -MIICpTCCAkygAwIBAgIJAJoVb07aGgNaMAoGCCqGSM49BAMCMIGwMQswCQYDVQQG -EwJJTDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwISGVyemxpeWExFDAS -BgNVBAoMC0lEQyBIZXJsaXlhMR8wHQYDVQQLDBZNZWVya2F0IFZvdGluZyBQcm9q -ZWN0MRgwFgYDVQQDDA9UZXN0aW5nIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGXRl -c3RpbmctY2FAZmFjdGNlbnRlci5vcmcwHhcNMTUxMTExMTUzODE4WhcNMjUxMTA4 -MTUzODE4WjCBsDELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUxETAP -BgNVBAcMCEhlcnpsaXlhMRQwEgYDVQQKDAtJREMgSGVybGl5YTEfMB0GA1UECwwW -TWVlcmthdCBWb3RpbmcgUHJvamVjdDEYMBYGA1UEAwwPVGVzdGluZyBSb290IENB -MSgwJgYJKoZIhvcNAQkBFhl0ZXN0aW5nLWNhQGZhY3RjZW50ZXIub3JnMFYwEAYH -KoZIzj0CAQYFK4EEAAoDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+z -FgFwvWHoWf6yJsSBymviB5yUaH+cE+/3LXlGbpRzYKLBYaNQME4wHQYDVR0OBBYE -FIkP0vV8uZfgD0IGguxhefc4/LWiMB8GA1UdIwQYMBaAFIkP0vV8uZfgD0IGguxh -efc4/LWiMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgNftHrW30Git8 -VFQKyMCkasauSpEHpAGdcRAhRHqUQMUCIDxw++trz/Iv8818xVB1ARr9EQAmH0aC -7MHETGuiBC7L ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICpTCCAkygAwIBAgIJAJoVb07aGgNaMAoGCCqGSM49BAMCMIGwMQswCQYDVQQG +EwJJTDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwISGVyemxpeWExFDAS +BgNVBAoMC0lEQyBIZXJsaXlhMR8wHQYDVQQLDBZNZWVya2F0IFZvdGluZyBQcm9q +ZWN0MRgwFgYDVQQDDA9UZXN0aW5nIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGXRl +c3RpbmctY2FAZmFjdGNlbnRlci5vcmcwHhcNMTUxMTExMTUzODE4WhcNMjUxMTA4 +MTUzODE4WjCBsDELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUxETAP +BgNVBAcMCEhlcnpsaXlhMRQwEgYDVQQKDAtJREMgSGVybGl5YTEfMB0GA1UECwwW +TWVlcmthdCBWb3RpbmcgUHJvamVjdDEYMBYGA1UEAwwPVGVzdGluZyBSb290IENB +MSgwJgYJKoZIhvcNAQkBFhl0ZXN0aW5nLWNhQGZhY3RjZW50ZXIub3JnMFYwEAYH +KoZIzj0CAQYFK4EEAAoDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+z +FgFwvWHoWf6yJsSBymviB5yUaH+cE+/3LXlGbpRzYKLBYaNQME4wHQYDVR0OBBYE +FIkP0vV8uZfgD0IGguxhefc4/LWiMB8GA1UdIwQYMBaAFIkP0vV8uZfgD0IGguxh +efc4/LWiMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgNftHrW30Git8 +VFQKyMCkasauSpEHpAGdcRAhRHqUQMUCIDxw++trz/Iv8818xVB1ARr9EQAmH0aC +7MHETGuiBC7L +-----END CERTIFICATE----- diff --git a/meerkat-common/src/test/resources/certs/secp256k1.pem b/meerkat-common/src/test/resources/certs/secp256k1.pem index 32d952e..d707107 100644 --- a/meerkat-common/src/test/resources/certs/secp256k1.pem +++ b/meerkat-common/src/test/resources/certs/secp256k1.pem @@ -1,3 +1,3 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQACg== ------END EC PARAMETERS----- +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- diff --git a/polling-station/build.gradle b/polling-station/build.gradle index 34fe58d..d510d26 100644 --- a/polling-station/build.gradle +++ b/polling-station/build.gradle @@ -1,194 +1,194 @@ - -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 = "Meerkat polling-station application" - -// 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 =======*/ - -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() - - // 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 = "Meerkat polling-station application" + +// 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 =======*/ + +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() + + // 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 + } + } + } +} + + + diff --git a/restful-api-common/.gitignore b/restful-api-common/.gitignore index ae3c172..3e2fcc7 100644 --- a/restful-api-common/.gitignore +++ b/restful-api-common/.gitignore @@ -1 +1 @@ -/bin/ +/bin/ diff --git a/restful-api-common/build.gradle b/restful-api-common/build.gradle index 3c0ad1e..483790e 100644 --- a/restful-api-common/build.gradle +++ b/restful-api-common/build.gradle @@ -1,160 +1,160 @@ - -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' - -// Uncomment both lines below to define an application (must set mainClassName -//apply plugin: 'application' -//mainClassName='your.main.ApplicationClass' - -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 = "Common classes for implementing Meerkat's RESTful API" - -// Your project version -version = "0.0.1" - -version += "${isSnapshot ? '-SNAPSHOT' : ''}" - - -dependencies { - // Meerkat common - compile project(':meerkat-common') - - // Jersey for RESTful API - compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' - - // Logging - compile 'org.slf4j:slf4j-api:1.7.7' - runtime 'ch.qos.logback:logback-classic:1.1.2' - runtime 'ch.qos.logback:logback-core:1.1.2' - - // Google protobufs - compile 'com.google.protobuf:protobuf-java:3.+' - - testCompile 'junit:junit:4.+' - - runtime 'org.codehaus.groovy:groovy:2.4.+' -} - - -/*==== 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) - } -} - - - -/*=================================== - * 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' + +// Uncomment both lines below to define an application (must set mainClassName +//apply plugin: 'application' +//mainClassName='your.main.ApplicationClass' + +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 = "Common classes for implementing Meerkat's RESTful API" + +// Your project version +version = "0.0.1" + +version += "${isSnapshot ? '-SNAPSHOT' : ''}" + + +dependencies { + // Meerkat common + compile project(':meerkat-common') + + // Jersey for RESTful API + compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' + + // Logging + compile 'org.slf4j:slf4j-api:1.7.7' + runtime 'ch.qos.logback:logback-classic:1.1.2' + runtime 'ch.qos.logback:logback-core:1.1.2' + + // Google protobufs + compile 'com.google.protobuf:protobuf-java:3.+' + + testCompile 'junit:junit:4.+' + + runtime 'org.codehaus.groovy:groovy:2.4.+' +} + + +/*==== 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) + } +} + + + +/*=================================== + * 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 + } + } + } +} + + + diff --git a/restful-api-common/src/main/java/meerkat/rest/Constants.java b/restful-api-common/src/main/java/meerkat/rest/Constants.java index 73ed7d1..239b957 100644 --- a/restful-api-common/src/main/java/meerkat/rest/Constants.java +++ b/restful-api-common/src/main/java/meerkat/rest/Constants.java @@ -1,12 +1,12 @@ -package meerkat.rest; - -/** - * Created by talm on 10/11/15. - */ -public interface Constants { - public static final String MEDIATYPE_PROTOBUF = "application/x-protobuf"; - - public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; - public static final String READ_MESSAGES_PATH = "/readmessages"; - public static final String POST_MESSAGE_PATH = "/postmessage"; -} +package meerkat.rest; + +/** + * Created by talm on 10/11/15. + */ +public interface Constants { + public static final String MEDIATYPE_PROTOBUF = "application/x-protobuf"; + + public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; + public static final String READ_MESSAGES_PATH = "/readmessages"; + public static final String POST_MESSAGE_PATH = "/postmessage"; +} diff --git a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java index d09e213..a139e17 100644 --- a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java +++ b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java @@ -1,41 +1,41 @@ -package meerkat.rest; - -import com.google.protobuf.GeneratedMessage; -import com.google.protobuf.Message; - - -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyReader; -import javax.ws.rs.ext.Provider; -import java.io.IOException; -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -import static meerkat.rest.Constants.*; - -@Provider -@Consumes(MEDIATYPE_PROTOBUF) -public class ProtobufMessageBodyReader implements MessageBodyReader { - @Override - public boolean isReadable(Class type, Type genericType, Annotation[] annotations, - MediaType mediaType) { - return Message.class.isAssignableFrom(type); - } - - @Override - public Message readFrom(Class type, Type genericType, Annotation[] annotations, - MediaType mediaType, MultivaluedMap httpHeaders, - InputStream entityStream) throws IOException, WebApplicationException { - try { - Method newBuilder = type.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type); - return builder.mergeFrom(entityStream).build(); - } catch (Exception e) { - throw new WebApplicationException(e); - } - } -} +package meerkat.rest; + +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.Message; + + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import static meerkat.rest.Constants.*; + +@Provider +@Consumes(MEDIATYPE_PROTOBUF) +public class ProtobufMessageBodyReader implements MessageBodyReader { + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, + MediaType mediaType) { + return Message.class.isAssignableFrom(type); + } + + @Override + public Message readFrom(Class type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap httpHeaders, + InputStream entityStream) throws IOException, WebApplicationException { + try { + Method newBuilder = type.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type); + return builder.mergeFrom(entityStream).build(); + } catch (Exception e) { + throw new WebApplicationException(e); + } + } +} diff --git a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyWriter.java b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyWriter.java index b8ea503..2397b4b 100644 --- a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyWriter.java +++ b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyWriter.java @@ -1,41 +1,41 @@ -package meerkat.rest; - -import com.google.protobuf.Message; - -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -import static meerkat.rest.Constants.*; - -@Provider -@Produces(MEDIATYPE_PROTOBUF) -public class ProtobufMessageBodyWriter implements MessageBodyWriter { - @Override - public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, - MediaType mediaType) { - return Message.class.isAssignableFrom(type); - } - - @Override - public long getSize(Message message, Class type, Type genericType, Annotation[] annotations, - MediaType mediaType) { - return -1; - } - - @Override - public void writeTo(Message message, Class type, Type genericType, Annotation[] annotations, - MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) - throws IOException, WebApplicationException { - message.writeTo(entityStream); - } -} - - +package meerkat.rest; + +import com.google.protobuf.Message; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import static meerkat.rest.Constants.*; + +@Provider +@Produces(MEDIATYPE_PROTOBUF) +public class ProtobufMessageBodyWriter implements MessageBodyWriter { + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, + MediaType mediaType) { + return Message.class.isAssignableFrom(type); + } + + @Override + public long getSize(Message message, Class type, Type genericType, Annotation[] annotations, + MediaType mediaType) { + return -1; + } + + @Override + public void writeTo(Message message, Class type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + message.writeTo(entityStream); + } +} + + diff --git a/settings.gradle b/settings.gradle index 5f81a65..f019032 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,8 @@ -include 'meerkat-common' -include 'voting-booth' -include 'bulletin-board-server' -include 'polling-station' -include 'restful-api-common' -include 'bulletin-board-client' -include 'destributed-key-generation' - +include 'meerkat-common' +include 'voting-booth' +include 'bulletin-board-server' +include 'polling-station' +include 'restful-api-common' +include 'bulletin-board-client' +include 'destributed-key-generation' + diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 70d7340..241e3c3 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -1,193 +1,193 @@ - -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 = "Meerkat voting booth application" - -// 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 =======*/ - -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() - - // 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 = "Meerkat voting booth application" + +// 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 =======*/ + +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() + + // 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 + } + } + } +} + + + From 0ae9719bc501d9baadd579b807e64ac0f3d8d8f2 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 8 Apr 2016 15:03:32 +0300 Subject: [PATCH 036/106] generic group + wait instead of sleep --- .../src/main/java/Communication/Channel.java | 28 - .../src/main/java/Communication/Network.java | 75 -- .../src/main/java/Communication/User.java | 74 -- .../VerifiableSecretSharing.java | 102 --- .../SecureDistributedKeyGeneration.java | 141 --- .../SecureDistributedKeyGenerationParty.java | 29 - .../DistributedKeyGenerationUser.java | 13 - .../java/UserInterface/SecretSharingUser.java | 14 - .../VerifiableSecretSharingUser.java | 16 - .../java/meerkat/crypto/KeyGeneration.java | 11 + .../java/meerkat/crypto/SecretSharing.java | 7 + .../Communication/ChannelImpl.java | 108 +++ .../Communication/MailHandler.java | 114 ++- .../Communication/MessageHandler.java | 30 +- .../gjkr_secure_protocol/MailHandler.java} | 126 +-- .../gjkr_secure_protocol/Party.java | 29 + .../gjkr_secure_protocol/Protocol.java | 165 ++++ .../gjkr_secure_protocol/User.java} | 633 ++++++------- .../joint_feldman_protocol/MailHandler.java} | 98 +- .../joint_feldman_protocol/Party.java} | 67 +- .../joint_feldman_protocol/Protocol.java} | 636 +++++++------ .../joint_feldman_protocol/User.java} | 847 ++++++++++-------- .../VerifiableSecretSharing.java | 108 +++ .../shamir}/LagrangePolynomial.java | 132 +-- .../secret_shring/shamir}/Polynomial.java | 416 ++++----- .../secret_shring/shamir}/SecretSharing.java | 222 ++--- .../crypto/utilitis}/Arithmetic.java | 36 +- .../java/meerkat/crypto/utilitis/Channel.java | 26 + .../crypto/utilitis/concrete}/Fp.java | 77 +- .../src/test/java/Utils/ChannelImpl.java | 108 +++ .../Arithmetics => test/java/Utils}/Z.java | 59 +- .../SDKGMaliciousUserImpl.java | 123 +-- .../gjkr_secure_protocol}/SDKGTest.java | 358 ++++---- .../SDKGUserImplAbort.java | 128 ++- .../DKGMaliciousUser.java} | 145 +-- .../joint_feldman_protocol}/DKGTest.java | 354 ++++---- .../DKGUserImplAbort.java | 126 +-- .../VerifiableSecretSharingTest.java | 135 +-- .../shamir}/PolynomialTests/AddTest.java | 92 +- .../PolynomialTests/InterpolationTest.java | 136 +-- .../PolynomialTests/MulByConstTest.java | 96 +- .../shamir}/PolynomialTests/MulTest.java | 96 +- .../shamir}/SecretSharingTest.java | 127 +-- 43 files changed, 3351 insertions(+), 3112 deletions(-) delete mode 100644 destributed-key-generation/src/main/java/Communication/Channel.java delete mode 100644 destributed-key-generation/src/main/java/Communication/Network.java delete mode 100644 destributed-key-generation/src/main/java/Communication/User.java delete mode 100644 destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java delete mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java delete mode 100644 destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java delete mode 100644 destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java delete mode 100644 destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java delete mode 100644 destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java rename destributed-key-generation/src/main/java/{ => meerkat/crypto/concrete/distributed_key_generation}/Communication/MailHandler.java (70%) rename destributed-key-generation/src/main/java/{ => meerkat/crypto/concrete/distributed_key_generation}/Communication/MessageHandler.java (89%) rename destributed-key-generation/src/main/java/{SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java => meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java} (71%) create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java rename destributed-key-generation/src/main/java/{SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java => meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java} (58%) rename destributed-key-generation/src/main/java/{JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java} (74%) rename destributed-key-generation/src/main/java/{JointFeldmanProtocol/DistributedKeyGenerationParty.java => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java} (61%) rename destributed-key-generation/src/main/java/{JointFeldmanProtocol/DistributedKeyGeneration.java => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java} (51%) rename destributed-key-generation/src/main/java/{JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java} (61%) create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java rename destributed-key-generation/src/main/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/LagrangePolynomial.java (94%) rename destributed-key-generation/src/main/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/Polynomial.java (94%) rename destributed-key-generation/src/main/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/SecretSharing.java (84%) rename destributed-key-generation/src/main/java/{Arithmetics => meerkat/crypto/utilitis}/Arithmetic.java (85%) create mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java rename destributed-key-generation/src/main/java/{Arithmetics => meerkat/crypto/utilitis/concrete}/Fp.java (90%) create mode 100644 destributed-key-generation/src/test/java/Utils/ChannelImpl.java rename destributed-key-generation/src/{main/java/Arithmetics => test/java/Utils}/Z.java (84%) rename destributed-key-generation/src/test/java/{SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem => meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol}/SDKGMaliciousUserImpl.java (53%) rename destributed-key-generation/src/test/java/{SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem => meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol}/SDKGTest.java (77%) rename destributed-key-generation/src/test/java/{SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem => meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol}/SDKGUserImplAbort.java (66%) rename destributed-key-generation/src/test/java/{JointFeldmanProtocol/DKGMaliciousUserImpl.java => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java} (59%) rename destributed-key-generation/src/test/java/{JointFeldmanProtocol => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol}/DKGTest.java (78%) rename destributed-key-generation/src/test/java/{JointFeldmanProtocol => meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol}/DKGUserImplAbort.java (75%) rename destributed-key-generation/src/test/java/{FeldmanVerifiableSecretSharing => meerkat/crypto/concrete/secret_shring/feldman_verifiable}/VerifiableSecretSharingTest.java (85%) rename destributed-key-generation/src/test/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/PolynomialTests/AddTest.java (89%) rename destributed-key-generation/src/test/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/PolynomialTests/InterpolationTest.java (89%) rename destributed-key-generation/src/test/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/PolynomialTests/MulByConstTest.java (89%) rename destributed-key-generation/src/test/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/PolynomialTests/MulTest.java (89%) rename destributed-key-generation/src/test/java/{ShamirSecretSharing => meerkat/crypto/concrete/secret_shring/shamir}/SecretSharingTest.java (81%) diff --git a/destributed-key-generation/src/main/java/Communication/Channel.java b/destributed-key-generation/src/main/java/Communication/Channel.java deleted file mode 100644 index cedb213..0000000 --- a/destributed-key-generation/src/main/java/Communication/Channel.java +++ /dev/null @@ -1,28 +0,0 @@ -package Communication; - -/** - * A generic commmunication channel that supports point-to-point and broadcast operation - */ -// -//public interface Channel { -// public interface ReceiverCallback { -// public void receiveMessage(UserID fromUser, boolean isBroadcast, Message message); -// } -// -// public void sendMessage(UserID destUser, Message msg); -// -// /** -// * Block until a message is available (optional). -// * @return -// */ -// public Message getNextMessageBlocking(long timeout); -// -// -// /** -// * Register a callback to handle received messages. -// * The callback is called in the Channel thread, so no long processing should -// * occur in the callback method. -// * @param callback -// */ -// public void registerReceiverCallback(ReceiverCallback callback); -//} diff --git a/destributed-key-generation/src/main/java/Communication/Network.java b/destributed-key-generation/src/main/java/Communication/Network.java deleted file mode 100644 index 8de25b3..0000000 --- a/destributed-key-generation/src/main/java/Communication/Network.java +++ /dev/null @@ -1,75 +0,0 @@ -package Communication; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages.*; - -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ArrayBlockingQueue; -/** - * Created by Tzlil on 2/7/2016. - * Joint Feldamn protocol assumes all parties can communicate throw broadcast channel - * and private channel (for each pair) - * this class simulates it - */ -// TODO: Delete -// TODO: Move this implementation to tests -public class Network { - - protected final User[] users; - protected final int n; - protected final Set availableIDs; - public static final int BROADCAST = 0; - - - public Network(int n) { - this.n = n; - this.users = new User[n]; - this.availableIDs = new HashSet(); - for (int id = 1; id <= n; id++){ - availableIDs.add(id); - } - } - - public User connect(MailHandler mailHandler,int id){ - if (!availableIDs.contains(id)) - return null; - availableIDs.remove(id); - users[id - 1] = new User(id,this,mailHandler); - return users[id - 1]; - } - - protected boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ - if(destination < 1 || destination > n) - return false; - User user = users[destination - 1]; - if (user == null) - return false; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(destination) - .setIsPrivate(true) - .setType(type) - .setMessage(message.toByteString()) - .build(); - return user.mailbox.add(mail); - } - - protected void sendBroadcast(User sender,Mail.Type type,Message message){ - User user; - Mail mail = Mail.newBuilder() - .setSender(sender.getID()) - .setDestination(BROADCAST) - .setIsPrivate(false) - .setType(type) - .setMessage(message.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - user = users[i]; - user.mailbox.add(mail); - } - } - -} diff --git a/destributed-key-generation/src/main/java/Communication/User.java b/destributed-key-generation/src/main/java/Communication/User.java deleted file mode 100644 index 1eb6e4a..0000000 --- a/destributed-key-generation/src/main/java/Communication/User.java +++ /dev/null @@ -1,74 +0,0 @@ -package Communication; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Created by Tzlil on 2/14/2016. - */ -// TODO: Change nane to network - -public class User{ - /* - * My view of - */ - - - - protected final MailHandler mailHandler; - protected final Queue mailbox; - protected final int ID; - protected final Thread receiverThread; - private final Network network; - - protected User(int ID, Network network, MailHandler mailHandler) { - this.mailbox = new ArrayBlockingQueue( network.n * network.n * network.n); - this.ID = ID; - this.mailHandler = mailHandler; - this.receiverThread = new Thread(new Receiver()); - this.network = network; - } - - public boolean send(int id, DKGMessages.Mail.Type type, Message message){ - return network.sendMessage(this,id,type,message); - } - - public void broadcast(DKGMessages.Mail.Type type, Message message){ - network.sendBroadcast(this,type,message); - } - public MailHandler getMailHandler(){ - return mailHandler; - } - public void setMessageHandler(MessageHandler messageHandler) { - mailHandler.setMessageHandler(messageHandler); - } - - public int getID() { - return ID; - } - public Thread getReceiverThread(){ - return receiverThread; - } - private class Receiver implements Runnable{ - @Override - public void run() { - while (true){ - if (!mailbox.isEmpty()){ - mailHandler.handel(mailbox.poll()); - }else{ - try { - Thread.sleep(30); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - } - - -} diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java deleted file mode 100644 index 7b5b7ad..0000000 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharing.java +++ /dev/null @@ -1,102 +0,0 @@ -package FeldmanVerifiableSecretSharing; - -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; - -import org.factcenter.qilin.primitives.Group; -import java.util.Arrays; -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. - * - * TODO: Add link to paper - * - */ -// TODO: Use Group rather than fix to biginteger (allow using EC groups for better comm. complexity) -public class VerifiableSecretSharing extends SecretSharing { - protected final Group group; - protected final BigInteger g; // public generator of group - protected final BigInteger[] commitmentsArray; - /** - * @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 x, Random random, BigInteger q, BigInteger g - , Group group) { - super(t, n, x, random,q); - this.g = g; - this.group = group; - assert (this.group.contains(g)); - this.commitmentsArray = generateCommitments(); - } - - /** - * TODO: comment - * @return commitments[i] = g ^ polynomial.coefficients[i] - */ - private BigInteger[] generateCommitments() { - - Polynomial polynomial = getPolynomial(); - BigInteger[] coefficients = polynomial.getCoefficients(); - BigInteger[] commitments = new BigInteger[coefficients.length]; - for (int i = 0 ; i < commitments.length;i++){ - commitments[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 BigInteger computeVerificationValue(int j, BigInteger[] commitments, Group group) { - BigInteger v = group.zero(); - BigInteger power = BigInteger.ONE; - BigInteger J = BigInteger.valueOf(j); - for (int k = 0 ; k < commitments.length ; k ++){ - v = group.add(v,group.multiply(commitments[k],power)); - power = power.multiply(J); - } - return v; - } - - // TODO: Add verify method. - - /** - * getter - * @return generator of group - */ - public BigInteger getGenerator() { - return g; - } - - /** - * getter - * @return group - */ - public Group getGroup(){ - return group; - } - - /** - * getter - * @return copy of commitmentsArray - */ - public BigInteger[] getCommitmentsArray() { - return Arrays.copyOf(commitmentsArray, commitmentsArray.length); - } - -} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java deleted file mode 100644 index 9aefeb5..0000000 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGeneration.java +++ /dev/null @@ -1,141 +0,0 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.User; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import JointFeldmanProtocol.DistributedKeyGeneration; -import ShamirSecretSharing.Polynomial; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/16/2016. - * TODO: comments - * TODO: put Channel (User) in constructor - */ -public class SecureDistributedKeyGeneration extends DistributedKeyGeneration { - - private VerifiableSecretSharing maskingShares; - private final BigInteger h; - private SecureDistributedKeyGenerationParty[] parties; - - public SecureDistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g - , BigInteger h, Group group, int id) { - super(t, n, zi, random, q, g, group, id); - 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 SecureDistributedKeyGenerationParty[n]; - for (int i = 1; i <= n ; i++){ - this.parties[i - 1] = new SecureDistributedKeyGenerationParty(i,n,t); - } - this.parties[id - 1].share = getShare(id); - this.parties[id - 1].shareT = maskingShares.getShare(id); - super.setParties(parties); - } - - protected SecureDistributedKeyGenerationParty[] getParties(){ - return parties; - } - - protected void setParties(SecureDistributedKeyGenerationParty[] parties) { - super.setParties(parties); - this.parties = parties; - } - - - @Override - public void sendSecret(User user, int j) { - Polynomial.Point secret = getShare(j); - Polynomial.Point secretT = maskingShares.getShare(j); - DKGMessages.DoubleSecretMessage doubleSecretMessage = doubleShareMessage(id,j,secret,secretT); - // TODO: Change SECRET to SHARE - user.send(j, DKGMessages.Mail.Type.SECRET, doubleSecretMessage); - } - - - public boolean isValidShare(int i){ - SecureDistributedKeyGenerationParty party = parties[i - 1]; - return isValidShare(party.share, party.shareT, party.verifiableValues, id); - } - - /** - * TODO: comment - * @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, BigInteger[] verificationValues, int j){ - try { - BigInteger v = computeVerificationValue(j, verificationValues, group); - BigInteger exp = group.add(group.multiply(g, share.y), group.multiply(h, shareT.y)); - return exp.equals(v); - } - catch (NullPointerException e){ - return false; - } - } - - // TODO: comment - private void broadcastComplaint(User user,Polynomial.Point share,Polynomial.Point shareT,int i){ - DKGMessages.DoubleSecretMessage complaint = doubleShareMessage(i,id,share,shareT); - user.broadcast(DKGMessages.Mail.Type.COMPLAINT,complaint); - } - - /** - * stage4.3 according to the protocol - * if check fails for index i, Pj - */ - public void computeAndBroadcastComplaints(User user, Set QUAL){ - SecureDistributedKeyGenerationParty party; - for (int i : QUAL) { - party = parties[i - 1]; - if (i != id) { - if (!super.isValidSecret(party.share, party.commitments, id)) { - broadcastComplaint(user, party.share, party.shareT, i); - } - } - } - } - - public void broadcastVerificationValues(User user){ - BigInteger[] verificationValues = new BigInteger[t + 1]; - BigInteger[] hBaseCommitments = maskingShares.getCommitmentsArray(); - for (int k = 0 ; k < verificationValues.length ; k++){ - verificationValues[k] = group.add(commitmentsArray[k],hBaseCommitments[k]); - } - broadcastCommitments(user,verificationValues); - } - - private DKGMessages.DoubleSecretMessage doubleShareMessage(int i, int j, Polynomial.Point secret, Polynomial.Point secretT){ - DKGMessages.DoubleSecretMessage doubleSecretMessage = DKGMessages.DoubleSecretMessage.newBuilder() - .setI(i) - .setJ(j) - .setSecret(ByteString.copyFrom(secret.y.toByteArray())) - .setSecretT(ByteString.copyFrom(secretT.y.toByteArray())) - .build(); - return doubleSecretMessage; - } - - @Override - public void broadcastComplaintAnswer(User user, int j) { - DKGMessages.DoubleSecretMessage answer = doubleShareMessage(id,j,getShare(j) - , maskingShares.getShare(j)); - user.broadcast(DKGMessages.Mail.Type.ANSWER,answer); - } - - public void broadcastAnswer(User user,Polynomial.Point secret,Polynomial.Point secretT,int i){ - DKGMessages.DoubleSecretMessage complaint = doubleShareMessage(i,id,secret,secretT); - user.broadcast(DKGMessages.Mail.Type.ANSWER,complaint); - } - - public BigInteger getH() { - return h; - } -} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java deleted file mode 100644 index fc2e8e3..0000000 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationParty.java +++ /dev/null @@ -1,29 +0,0 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import JointFeldmanProtocol.DistributedKeyGenerationParty; -import ShamirSecretSharing.Polynomial; - -import java.math.BigInteger; -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 SecureDistributedKeyGenerationParty extends DistributedKeyGenerationParty { - public Polynomial.Point shareT; - public boolean ysDoneFlag; - public BigInteger[] verifiableValues; - public Set restoreSharesSet; - public SecureDistributedKeyGenerationParty(int id, int n, int t) { - super(id, n, t); - this.shareT = null; - this.ysDoneFlag = false; - this.verifiableValues = new BigInteger[t + 1]; - this.restoreSharesSet = new HashSet(); - } -} diff --git a/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java b/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java deleted file mode 100644 index 9fcdbf6..0000000 --- a/destributed-key-generation/src/main/java/UserInterface/DistributedKeyGenerationUser.java +++ /dev/null @@ -1,13 +0,0 @@ -package UserInterface; - -import java.math.BigInteger; -import java.util.Set; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface DistributedKeyGenerationUser extends VerifiableSecretSharingUser { - - BigInteger getPublicValue(); - Set getQUAL(); -} diff --git a/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java deleted file mode 100644 index e5462a0..0000000 --- a/destributed-key-generation/src/main/java/UserInterface/SecretSharingUser.java +++ /dev/null @@ -1,14 +0,0 @@ -package UserInterface; - -import ShamirSecretSharing.Polynomial; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface SecretSharingUser extends Runnable { - - Polynomial.Point getShare(); - int getID(); - int getN(); - int getT(); -} diff --git a/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java b/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java deleted file mode 100644 index a8e4e96..0000000 --- a/destributed-key-generation/src/main/java/UserInterface/VerifiableSecretSharingUser.java +++ /dev/null @@ -1,16 +0,0 @@ -package UserInterface; - -import UserInterface.SecretSharingUser; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 2/21/2016. - */ -public interface VerifiableSecretSharingUser extends SecretSharingUser { - - BigInteger[] getCommitments(); - BigInteger getGenerator(); - Group getGroup(); -} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java b/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java new file mode 100644 index 0000000..a6db4f9 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java @@ -0,0 +1,11 @@ +package meerkat.crypto; + +import java.util.Random; + +/** + * Created by Tzlil on 4/8/2016. + */ +public interface KeyGeneration { + + T generateKey(Random random); +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java b/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java new file mode 100644 index 0000000..e7619b6 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java @@ -0,0 +1,7 @@ +package meerkat.crypto; + +/** + * Created by Tzlil on 4/8/2016. + */ +public class SecretSharing { +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java new file mode 100644 index 0000000..04fa4ef --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java @@ -0,0 +1,108 @@ +package meerkat.crypto.concrete.distributed_key_generation.Communication; + +import com.google.protobuf.Message; +import meerkat.crypto.utilitis.Channel; +import meerkat.protobuf.DKGMessages; + +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +/** + * Created by Tzlil on 2/14/2016. + */ +// TODO: Change nane to network + +public class ChannelImpl implements Channel { + + public static int BROADCAST = 0; + private static ChannelImpl[] channels = null; + + protected final Queue mailbox; + protected final int id; + protected final int n; + protected Thread receiverThread; + + + public ChannelImpl(int id, int n) { + if (channels == null){ + channels = new ChannelImpl[n]; + } + this.mailbox = new ArrayBlockingQueue( n * n * n); + this.id = id; + this.n = n; + channels[id - 1] = this; + } + + public int getId() { + return id; + } + + @Override + public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg) { + if(destUser < 1 || destUser > n) + return; + ChannelImpl channel = channels[destUser - 1]; + if (channel == null) + return; + DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + .setSender(id) + .setDestination(destUser) + .setIsPrivate(true) + .setType(type) + .setMessage(msg.toByteString()) + .build(); + synchronized (channel.mailbox) { + channel.mailbox.add(mail); + channel.mailbox.notify(); + } + } + + @Override + public void broadcastMessage(DKGMessages.Mail.Type type,Message msg) { + ChannelImpl channel; + DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + .setSender(id) + .setDestination(BROADCAST) + .setIsPrivate(false) + .setType(type) + .setMessage(msg.toByteString()) + .build(); + for (int i = 0 ; i < n ; i++){ + channel = channels[i]; + synchronized (channel.mailbox) { + channel.mailbox.add(mail); + channel.mailbox.notify(); + } + } + } + + @Override + public void registerReceiverCallback(final ReceiverCallback callback) { + try{ + receiverThread.interrupt(); + }catch (Exception e){ + //do nothing + } + receiverThread = new Thread(new Runnable() { + @Override + public void run() { + while (true){ + try { + synchronized (mailbox) { + while (!mailbox.isEmpty()) { + callback.receiveMail(mailbox.remove()); + } + mailbox.wait(); + } + } catch (InterruptedException e) { + //do nothing + } + } + } + }); + receiverThread.start(); + } + + + +} diff --git a/destributed-key-generation/src/main/java/Communication/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java similarity index 70% rename from destributed-key-generation/src/main/java/Communication/MailHandler.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java index 23fd840..b01801f 100644 --- a/destributed-key-generation/src/main/java/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java @@ -1,58 +1,56 @@ -package Communication; - -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/14/2016. - */ -public abstract class MailHandler { - - private MessageHandler messageHandler; - public MailHandler(MessageHandler messageHandler){ - this.messageHandler = messageHandler; - } - - public abstract Message extractMessage(DKGMessages.Mail mail); - - public void handel(DKGMessages.Mail mail){ - - Message message = extractMessage(mail); - if (message == null) - return; - - switch (mail.getType()) { - case SECRET: - messageHandler.handleSecretMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case COMMITMENT: - messageHandler.handleCommitmentMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case DONE: - messageHandler.handleDoneMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case COMPLAINT: - messageHandler.handleComplaintMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case ANSWER: - messageHandler.handleAnswerMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - case ABORT: - messageHandler.handleAbortMessage(mail.getSender(), mail.getDestination() == Network.BROADCAST - , message); - break; - default: - break; - } - - - } - public void setMessageHandler(MessageHandler messageHandler) { - this.messageHandler = messageHandler; - } -} +package meerkat.crypto.concrete.distributed_key_generation.Communication; + +import com.google.protobuf.Message; +import meerkat.crypto.utilitis.Channel; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/14/2016. + */ +public abstract class MailHandler implements Channel.ReceiverCallback{ + + private MessageHandler messageHandler; + public MailHandler(MessageHandler messageHandler){ + this.messageHandler = messageHandler; + } + + public abstract Message extractMessage(DKGMessages.Mail mail); + + public void receiveMail(DKGMessages.Mail mail){ + + Message message = extractMessage(mail); + if (message == null) + return; + + switch (mail.getType()) { + case SHARE: + messageHandler.handleSecretMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + case COMMITMENT: + messageHandler.handleCommitmentMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + case DONE: + messageHandler.handleDoneMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + case COMPLAINT: + messageHandler.handleComplaintMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + case ANSWER: + messageHandler.handleAnswerMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + case ABORT: + messageHandler.handleAbortMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST + , message); + break; + default: + break; + } + + + } +} diff --git a/destributed-key-generation/src/main/java/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java similarity index 89% rename from destributed-key-generation/src/main/java/Communication/MessageHandler.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java index 2bbf3c4..74b453a 100644 --- a/destributed-key-generation/src/main/java/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java @@ -1,15 +1,15 @@ -package Communication; - -import com.google.protobuf.Message; - -/** - * Created by Tzlil on 2/14/2016. - */ -public interface MessageHandler { - void handleSecretMessage(int sender, boolean isBroadcast, Message message); - void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); - void handleComplaintMessage(int sender, boolean isBroadcast, Message message); - void handleDoneMessage(int sender, boolean isBroadcast, Message message); - void handleAnswerMessage(int sender, boolean isBroadcast, Message message); - void handleAbortMessage(int sender, boolean isBroadcast, Message message); -} +package meerkat.crypto.concrete.distributed_key_generation.Communication; + +import com.google.protobuf.Message; + +/** + * Created by Tzlil on 2/14/2016. + */ +public interface MessageHandler { + void handleSecretMessage(int sender, boolean isBroadcast, Message message); + void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); + void handleComplaintMessage(int sender, boolean isBroadcast, Message message); + void handleDoneMessage(int sender, boolean isBroadcast, Message message); + void handleAnswerMessage(int sender, boolean isBroadcast, Message message); + void handleAbortMessage(int sender, boolean isBroadcast, Message message); +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java similarity index 71% rename from destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java index 92dba85..4683f04 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java @@ -1,63 +1,63 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.MailHandler; -import Communication.MessageHandler; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/29/2016. - */ -public class SecureDistributedKeyGenerationMailHandler extends MailHandler { - - private boolean isStage4; - - public SecureDistributedKeyGenerationMailHandler(MessageHandler messageHandler) { - super(messageHandler); - this.isStage4 = false; - } - - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SECRET: - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - if(!isStage4) - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - else - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.DoubleSecretMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } - - public boolean isStage4() { - return isStage4; - } - - public void setStage4(boolean stage4) { - isStage4 = stage4; - } -} +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class MailHandler extends Communication.MailHandler { + + private boolean isStage4; + + public MailHandler(MessageHandler messageHandler) { + super(messageHandler); + this.isStage4 = false; + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SHARE: + message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + if(!isStage4) + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); + else + message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); + break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } + + public boolean isStage4() { + return isStage4; + } + + public void setStage4(boolean stage4) { + isStage4 = stage4; + } +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java new file mode 100644 index 0000000..82ebba8 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java @@ -0,0 +1,29 @@ +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGenerationParty; +import meerkat.crypto.concrete.secret_shring.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 extends DistributedKeyGenerationParty { + public Polynomial.Point shareT; + public boolean ysDoneFlag; + public ArrayList verifiableValues; + public Set recoverSharesSet; + public Party(int id, int n, int t) { + super(id, n, t); + this.shareT = null; + this.ysDoneFlag = false; + this.verifiableValues = new ArrayList(this.commitments); + this.recoverSharesSet = new HashSet(); + } +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java new file mode 100644 index 0000000..db0cc56 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java @@ -0,0 +1,165 @@ +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +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 extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol { + + private VerifiableSecretSharing maskingShares; + private final T h; + private Party[] parties; + + public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g + , T h, Group group, int id, ByteEncoder 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); + DKGMessages.DoubleShareMessage doubleSecretMessage = doubleShareMessage(id,j,secret,secretT); + // TODO: Change SHARE to SHARE + channel.sendMessage(j, DKGMessages.Mail.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 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){ + DKGMessages.DoubleShareMessage complaint = doubleShareMessage(i,id,share,shareT); + channel.broadcastMessage(DKGMessages.Mail.Type.COMPLAINT,complaint); + } + + /** + * stage4.3 according to the protocol + * if check fails for index i, Pj + */ + public void computeAndBroadcastComplaints(Set 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 verificationValues = new ArrayList(t+1); + ArrayList 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 doubleShareMessage + * @param i + * @param j + * @param share + * @param shareT + * @return + */ + + private DKGMessages.DoubleShareMessage doubleShareMessage(int i, int j, Polynomial.Point share, Polynomial.Point shareT){ + DKGMessages.DoubleShareMessage doubleShareMessage = DKGMessages.DoubleShareMessage.newBuilder() + .setI(i) + .setJ(j) + .setSecret(ByteString.copyFrom(share.y.toByteArray())) + .setSecretT(ByteString.copyFrom(shareT.y.toByteArray())) + .build(); + return doubleShareMessage; + } + + @Override + public void broadcastComplaintAnswer(int j) { + DKGMessages.DoubleShareMessage answer = doubleShareMessage(id,j,getShare(j) + , maskingShares.getShare(j)); + channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER,answer); + } + + public void broadcastAnswer(Polynomial.Point secret, Polynomial.Point secretT, int i){ + DKGMessages.DoubleShareMessage complaint = doubleShareMessage(i,id,secret,secretT); + channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER,complaint); + } + + /** + * getter + * @return h + */ + public T getH() { + return h; + } +} diff --git a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java similarity index 58% rename from destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java index 141b854..ac99b6e 100644 --- a/destributed-key-generation/src/main/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SecureDistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java @@ -1,307 +1,326 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import JointFeldmanProtocol.DistributedKeyGeneration; -import JointFeldmanProtocol.DistributedKeyGenerationUserImpl; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/16/2016. - */ -public class SecureDistributedKeyGenerationUserImpl extends DistributedKeyGenerationUserImpl { - - protected SecureDistributedKeyGenerationParty[] parties; - protected final SecureDistributedKeyGeneration sdkg; - private Arithmetic arithmetic; - private boolean isStage4; - - public SecureDistributedKeyGenerationUserImpl(SecureDistributedKeyGeneration sdkg, Network network) { - super(sdkg, network,new SecureDistributedKeyGenerationMailHandler(null)); - this.sdkg = sdkg; - this.messageHandler = new MessageHandler(); - this.user.setMessageHandler(this.messageHandler); - this.parties = sdkg.getParties(); - this.arithmetic = new Fp(sdkg.getQ()); - this.isStage4 = false; - } - - /** - * 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.broadcastVerificationValues(user); - sdkg.sendSecrets(user); - } - - @Override - protected void waitUntilStageOneCompleted(){ - super.waitUntilStageOneCompleted(); - // save the received commitments as verification values - BigInteger[] 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(user); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - } - - // TODO: ?? - private void resolveQualifyingPublicKey(){ - sdkg.broadcastCommitments(user); - // wait until all parties in QUAL broadcast their commitments or aborted - // TODO: in main run loop - for (int i:QUAL) { - for(int k = 0; k <= t; k++) { - while (parties[i - 1].commitments[k] == null && !parties[i - 1].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - sdkg.computeAndBroadcastComplaints(user,QUAL); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - - // wait until all parties in QUAL done or aborted - for (int i:QUAL) { - while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - - // broadcast i private secret foreach i in QUAL that aborted - for (int i:QUAL) { - if(parties[i - 1].aborted){ - sdkg.broadcastAnswer(user, parties[i - 1].share, parties[i - 1].shareT, i); - } - } - // wait until at least t + 1 secrets will received foreach i in QUAL that aborted - for (int i:QUAL) { - if(parties[i - 1].aborted){ - while (parties[i - 1].restoreSharesSet.size() <= t) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - // restore necessary information - for (int i = 0; i < n ; i++) { - if(parties[i].restoreSharesSet.isEmpty()){ - continue; - } - Polynomial.Point[] shares = new Polynomial.Point[t + 1]; - int j = 0; - for (Polynomial.Point share: parties[i].restoreSharesSet){ - 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[k] = group.multiply(g,coefficients[k]); - } - parties[i].share = new Polynomial.Point(BigInteger.valueOf(id),polynomial); - } - } - - /** - * notifies mail handler that stage 4 was started - */ - protected void setStage4(){ - this.isStage4 = true; - SecureDistributedKeyGenerationMailHandler handler = - (SecureDistributedKeyGenerationMailHandler)user.getMailHandler(); - handler.setStage4(true); - } - - @Override - protected void stage4() { - setStage4(); - resolveQualifyingPublicKey(); - super.stage4(); - } - - private class MessageHandler extends DistributedKeyGenerationUserImpl.MessageHandler{ - - /** - * as in super, with extension to double secret message - */ - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) - .build(); - return super.isValidSecretMessage(sender,isBroadcast,secretMessage); - } - - /** - * as in super, with extension to double secret message - */ - @Override - public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; - if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - parties[i - 1].share = extractSecret(id, doubleSecretMessage.getSecret()); - parties[i - 1].shareT = extractSecret(id, doubleSecretMessage.getSecretT()); - } - } - - /** - * 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, DKGMessages.DoubleSecretMessage doubleSecretMessage) { - if(!isStage4) { - DKGMessages.SecretMessage secretMessage = DKGMessages.SecretMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) - .build(); - return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); - }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); - } - } - - /** - * if !isStage4 as super, with extension to double secret message - * else saves secret - */ - @Override - public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleSecretMessage doubleSecretMessage = (DKGMessages.DoubleSecretMessage)message; - if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - int j = doubleSecretMessage.getJ(); - Polynomial.Point secret = extractSecret(j, doubleSecretMessage.getSecret()); - Polynomial.Point secretT = extractSecret(j, doubleSecretMessage.getSecretT()); - if (!isStage4) { - if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.NonDisqualified; - - } else { - parties[i - 1].complaints[j - 1] = DistributedKeyGeneration.ComplaintState.Disqualified; - } - if(j == id){ - parties[i - 1].share = secret; - parties[i - 1].shareT = secretT; - } - } else if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { - // TODO: Check that this is ok - parties[i - 1].restoreSharesSet.add(secret); - } - } - } - - /** - * 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; - } - } - - /** - * as in super with respect to protocol state - */ - @Override - public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) - super.handleDoneMessage(sender, isBroadcast, message); - else{ - if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].ysDoneFlag = true; - } - } - } - - /** - * 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, - DKGMessages.DoubleSecretMessage complaintMessage){ - int i = complaintMessage.getI(); - int j = complaintMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); - } - - /** - * 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 - */ - @Override - public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) { - super.handleComplaintMessage(sender, isBroadcast, message); - }else { - DKGMessages.DoubleSecretMessage ysComplaintMessage =(DKGMessages.DoubleSecretMessage)message; - if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { - int i = ysComplaintMessage.getI(); - int j = ysComplaintMessage.getJ(); - Polynomial.Point secret = extractSecret(i,ysComplaintMessage.getSecret()); - Polynomial.Point secretT = extractSecret(i,ysComplaintMessage.getSecretT()); - if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j) - && !dkg.isValidSecret(secret,parties[i - 1].commitments, j)) { - parties[i - 1].aborted = true; - } - } - } - } - } -} +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.concrete.Fp; +import meerkat.crypto.utilitis.Channel; +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +import java.math.BigInteger; +import java.util.ArrayList; + +/** + * Created by Tzlil on 3/16/2016. + */ +public class User extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User { + + protected Party[] parties; + protected final Protocol sdkg; + private Arithmetic arithmetic; + private boolean isStage4; + + public User(Protocol sdkg, Channel channel) { + super(sdkg, channel); + this.sdkg = sdkg; + this.parties = sdkg.getParties(); + this.arithmetic = new Fp(sdkg.getQ()); + this.isStage4 = false; + } + + @Override + protected void registerReceiverCallback(){ + this.mailHandler = new MailHandler(new MessageHandler()); + this.channel.registerReceiverCallback(mailHandler); + } + /** + * 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 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 + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); + } + + /** + * broadcast commitments and recover parties information if necessary + */ + private void resolveQualifyingPublicKey(){ + sdkg.broadcastCommitments(); + // wait until all parties in QUAL broadcast their commitments or aborted + for (int i:QUAL) { + for(int k = 0; k <= t; k++) { + synchronized (parties[i - 1]) { + while (parties[i - 1].commitments.get(k) == null && !parties[i - 1].aborted) { + try { + parties[i - 1].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + } + sdkg.computeAndBroadcastComplaints(QUAL); + //broadcast done message after all complaints + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); + + // wait until all parties in QUAL done or aborted + for (int i:QUAL) { + synchronized ((parties[i - 1])) { + while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { + try { + parties[i - 1].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + + // 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 + for (int i:QUAL) { + synchronized ((parties[i - 1])) { + if (parties[i - 1].aborted) { + while (parties[i - 1].recoverSharesSet.size() <= t) { + try { + parties[i - 1].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + } + + // 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 mail handler that stage 4 was started + */ + protected void setStage4(){ + this.isStage4 = true; + ((MailHandler)this.mailHandler).setStage4(true); + } + + @Override + protected void stage4() { + setStage4(); + resolveQualifyingPublicKey(); + super.stage4(); + } + + private class MessageHandler extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler { + + /** + * as in super, with extension to double secret message + */ + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleShareMessage doubleSecretMessage) { + DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidSecretMessage(sender,isBroadcast,secretMessage); + } + + /** + * as in super, with extension to double secret message + */ + @Override + public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message; + if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + synchronized (parties[i - 1]) { + parties[i - 1].share = extractShare(id, doubleSecretMessage.getSecret()); + parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getSecretT()); + parties[i - 1].notify(); + } + } + } + + /** + * 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, DKGMessages.DoubleShareMessage doubleSecretMessage) { + if(!isStage4) { + DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() + .setI(doubleSecretMessage.getI()) + .setJ(doubleSecretMessage.getJ()) + .setSecret(doubleSecretMessage.getSecret()) + .build(); + return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); + }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); + } + } + + /** + * if !isStage4 as super, with extension to double secret message + * else saves secret + */ + @Override + public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message; + if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + Polynomial.Point secret = extractShare(j, doubleSecretMessage.getSecret()); + Polynomial.Point secretT = extractShare(j, doubleSecretMessage.getSecretT()); + synchronized (parties[i - 1]) { + if (!isStage4) { + if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { + parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified; + + } else { + parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.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(); + } + } + } + + /** + * 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; + } + } + + /** + * as in super with respect to protocol state + */ + @Override + public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { + if(!isStage4) + super.handleDoneMessage(sender, isBroadcast, message); + else{ + if(isValidDoneMessage(sender,isBroadcast)) { + synchronized (parties[sender - 1]) { + parties[sender - 1].ysDoneFlag = true; + parties[sender - 1].notify(); + } + } + } + } + + /** + * 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, + DKGMessages.DoubleShareMessage complaintMessage){ + int i = complaintMessage.getI(); + int j = complaintMessage.getJ(); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); + } + + /** + * 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 + */ + @Override + public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { + if(!isStage4) { + super.handleComplaintMessage(sender, isBroadcast, message); + }else { + DKGMessages.DoubleShareMessage ysComplaintMessage =(DKGMessages.DoubleShareMessage)message; + if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { + int i = ysComplaintMessage.getI(); + int j = ysComplaintMessage.getJ(); + Polynomial.Point secret = extractShare(i,ysComplaintMessage.getSecret()); + Polynomial.Point secretT = extractShare(i,ysComplaintMessage.getSecretT()); + 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(); + } + } + } + } + } + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java similarity index 74% rename from destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java index f33959f..19c279e 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationMailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java @@ -1,49 +1,49 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.MessageHandler; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 2/29/2016. - */ -public class DistributedKeyGenerationMailHandler extends MailHandler { - - public DistributedKeyGenerationMailHandler(MessageHandler messageHandler) { - super(messageHandler); - } - - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SECRET: - message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.SecretMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import Communication.MailHandler; +import Communication.MessageHandler; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 2/29/2016. + */ +public class MailHandler extends Communication.MailHandler { + + public MailHandler(MessageHandler messageHandler) { + super(messageHandler); + } + + @Override + public Message extractMessage(DKGMessages.Mail mail) { + try { + Message message; + switch (mail.getType()) { + case SHARE: + message = DKGMessages.ShareMessage.parseFrom(mail.getMessage()); + break; + case COMMITMENT: + message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); + break; + case COMPLAINT: + message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); + break; + case DONE: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + case ANSWER: + message = DKGMessages.ShareMessage.parseFrom(mail.getMessage()); + break; + case ABORT: + message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); + break; + default: + return null; + } + return message; + } catch (InvalidProtocolBufferException e) { + return null; + } + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java similarity index 61% rename from destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java index 59ef1ea..b45d5b5 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationParty.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java @@ -1,32 +1,35 @@ -package JointFeldmanProtocol; - -import ShamirSecretSharing.Polynomial; - -import java.math.BigInteger; -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 - */ -// TODO: comments for every field. -public class DistributedKeyGenerationParty { - public final int id; - public Polynomial.Point share; - public BigInteger[] commitments; - public boolean doneFlag; - public DistributedKeyGeneration.ComplaintState[] complaints; - public boolean aborted; - - public DistributedKeyGenerationParty(int id, int n, int t) { - this.id = id; - this.share = null; - this.doneFlag = false; - this.complaints = new DistributedKeyGeneration.ComplaintState[n]; - Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.OK); - this.commitments = new BigInteger[t + 1]; - this.aborted = false; - } -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.concrete.secret_shring.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 + */ +// TODO: comments for every field. +public class Party { + public final int id; + public Polynomial.Point share; + public ArrayList commitments; + public boolean doneFlag; + public DistributedKeyGeneration.ComplaintState[] complaints; + public boolean aborted; + + public Party(int id, int n, int t) { + this.id = id; + this.share = null; + this.doneFlag = false; + this.complaints = new DistributedKeyGeneration.ComplaintState[n]; + Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.OK); + this.commitments = new ArrayList(t + 1); + for (int i = 0; i <= t ; i++){ + commitments.add(null); + } + this.aborted = false; + } +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java similarity index 51% rename from destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java index a60fd33..ba0a77b 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGeneration.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java @@ -1,280 +1,356 @@ -package JointFeldmanProtocol; - -import Communication.User; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import ShamirSecretSharing.Polynomial; -import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/14/2016. - */ -// TODO: Lots of comments... -// TODO: User Channel instead of User -public class DistributedKeyGeneration extends VerifiableSecretSharing { - 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 DistributedKeyGenerationParty[] parties; - - - // TODO: Copy comment - public DistributedKeyGeneration(int t, int n, BigInteger zi, Random random, BigInteger q, BigInteger g - , Group group, int id) { - super(t, n, zi, random, q, g,group); - this.id = id; - this.parties = new DistributedKeyGenerationParty[n]; - for (int i = 1; i <= n ; i++){ - this.parties[i - 1] = new DistributedKeyGenerationParty(i,n,t); - } - this.parties[id - 1].share = getShare(id); - } - - protected void setParties(DistributedKeyGenerationParty[] parties){ - this.parties = parties; - } - - protected DistributedKeyGenerationParty[] getParties(){ - return parties; - } - - /** - * stage1.1 according to the protocol - * Pi broadcasts Aik for k = 0,...,t. - */ - public void broadcastCommitments(User user){ - broadcastCommitments(user,commitmentsArray); - } - - public void broadcastCommitments(User user, BigInteger[] commitments){ - DKGMessages.CommitmentMessage commitmentMessage; - for (int k = 0; k <= t ; k++){ - commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() - .setCommitment(ByteString.copyFrom(commitments[k].toByteArray())) - .setK(k) - .build(); - user.broadcast(DKGMessages.Mail.Type.COMMITMENT, commitmentMessage); - } - } - - /** - * Send user j her secret share (of my polynomial) - * @param user - * @param j - */ - public void sendSecret(User user, int j){ - ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); - user.send(j, DKGMessages.Mail.Type.SECRET, - DKGMessages.SecretMessage.newBuilder() - .setI(id) - .setJ(j) - .setSecret(secret) - .build()); - } - - /** - * stage1.2 according to the protocol - * Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj. - */ - public void sendSecrets(User user){ - for (int j = 1; j <= n ; j++){ - if(j != id){ - sendSecret(user,j); - } - } - } - - /** - * TODO: comment - * @param i - * @return - */ - public boolean isValidSecret(int i){ - DistributedKeyGenerationParty party = parties[i - 1]; - return isValidSecret(party.share,party.commitments,id); - } - - /** - * TODO: Move to VerifiableSecretSharing - * @param secret - * @param commitments - * @param j - * @return computeVerificationValue(j,commitments,group) == g ^ secret.y mod q - */ - public boolean isValidSecret(Polynomial.Point secret, BigInteger[] commitments, int j){ - try{ - BigInteger v = computeVerificationValue(j,commitments,group); - return group.multiply(g,secret.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(User user){ - for (int i = 1; i <= n ; i++ ){ - if(i != id && !isValidSecret(i)) { - broadcastComplaint(user,i); - } - } - } - - private void broadcastComplaint(User user, int i){ - //message = new Message(Type.Complaint, j) - DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() - .setId(i) - .build(); - user.broadcast(DKGMessages.Mail.Type.COMPLAINT, complaint); - } - - public void broadcastComplaintAnswer(User user, int j){ - user.broadcast(DKGMessages.Mail.Type.ANSWER, DKGMessages.SecretMessage.newBuilder() - .setI(id) - .setJ(j) - .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) - .build()); - } - - /** - * stage3.1 according to the protocol - * if more than t players complain against a player Pi he is disqualified. - */ - public void answerAllComplainingPlayers(User user){ - ComplaintState[] complaints = parties[id - 1].complaints; - for (int i = 1; i <= n ; i++) { - switch (complaints[i - 1]) { - case Waiting: - broadcastComplaintAnswer(user,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 calcQUAL(){ - Set QUAL = new HashSet(); - boolean nonDisqualified; - int counter; - for (int i = 1; i <= n; i++){ - 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: - // TODO: Add test for false complaint - 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 BigInteger calcY(Set QUAL){ - BigInteger y = group.zero(); - for (int i : QUAL) { - y = group.add(y , parties[i - 1].commitments[0]); - } - return y; - } - - /** - * TODO: better comment. - * 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 BigInteger[] calcCommitments(Set QUAL){ - BigInteger[] commitments = new BigInteger[t + 1]; - Arrays.fill(commitments,group.zero()); - for (int i : QUAL) { - for (int k = 0; k <= t; k++){ - commitments[k] = group.add(commitments[k], parties[i - 1].commitments[k]); - } - } - return commitments; - } - - /** - * TODO: better comment. - * stage4.3 according to the protocol - * Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL - */ - public Polynomial.Point calcShare(Set QUAL){ - BigInteger xj = BigInteger.ZERO; - for (int i : QUAL) { - xj = xj.add(parties[i - 1].share.y); - } - return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); - } - - /** - * getter - * @return id - */ - public int getId() { - return id; - } - -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.utilitis.Channel; +import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import com.google.protobuf.ByteString; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; +import org.factcenter.qilin.util.ByteEncoder; + +import java.math.BigInteger; +import java.util.*; + +/** + * 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 extends VerifiableSecretSharing { + 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[] parties; + + /** + * communication object + */ + protected Channel channel; + + + /** + * Encode/Decode group elements + */ + protected final ByteEncoder 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. + */ + public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g + , Group group, int id, ByteEncoder byteEncoder) { + 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 = byteEncoder; + } + + /** + * 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 commitments){ + DKGMessages.CommitmentMessage commitmentMessage; + for (int k = 0; k <= t ; k++){ + commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() + .setCommitment(ByteString.copyFrom(encoder.encode(commitments.get(k)))) + .setK(k) + .build(); + channel.broadcastMessage(DKGMessages.Mail.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, DKGMessages.Mail.Type.SHARE, + DKGMessages.ShareMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(secret) + .build()); + } + + /** + * 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 party = 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 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) + DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() + .setId(i) + .build(); + channel.broadcastMessage(DKGMessages.Mail.Type.COMPLAINT, complaint); + } + + /** + * create an answer message for j and broadcast it + * @param j + */ + public void broadcastComplaintAnswer(int j){ + channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER, DKGMessages.ShareMessage.newBuilder() + .setI(id) + .setJ(j) + .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) + .build()); + } + + /** + * 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 calcQUAL(){ + Set QUAL = new HashSet(); + boolean nonDisqualified; + int counter; + for (int i = 1; i <= n; i++){ + 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 QUAL){ + T y = group.zero(); + for (int i : QUAL) { + 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 calcCommitments(Set QUAL){ + ArrayList commitments = new ArrayList(t+1); + T value; + for (int k = 0; k <= t; k++){ + value = group.zero(); + for (int i : QUAL) { + 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 QUAL){ + BigInteger xj = BigInteger.ZERO; + for (int i : QUAL) { + 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 getEncoder() { + return encoder; + } + +} diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java similarity index 61% rename from destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java index 6198f97..f225d59 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DistributedKeyGenerationUserImpl.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java @@ -1,393 +1,454 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.Network; -import Communication.User; -import ShamirSecretSharing.Polynomial; -import UserInterface.DistributedKeyGenerationUser; -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; -import org.factcenter.qilin.primitives.Group; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Set; -import JointFeldmanProtocol.DistributedKeyGeneration.ComplaintState; - -/** - * Created by Tzlil on 3/14/2016. - * TODO: Comments - * TODO: Replace polling with monitors/wait/notify (remember synchronization) - */ -public class DistributedKeyGenerationUserImpl implements DistributedKeyGenerationUser { - - // TODO: remove - protected final static int SleepTime = 300; - - protected final DistributedKeyGeneration dkg; - - protected final BigInteger g; - protected final Group group; - protected final int n; - protected final int t; - protected final int id; - - protected MessageHandler messageHandler; - protected final User user; - protected final DistributedKeyGenerationParty[] parties; - protected Set QUAL; // set of all non-disqualified parties - protected BigInteger[] commitments; // public verification values - protected Polynomial.Point share; // final share of the secrete - protected BigInteger y; // final public value - - public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network){ - this(dkg,network,new DistributedKeyGenerationMailHandler(null)); - } - public DistributedKeyGenerationUserImpl(DistributedKeyGeneration dkg, Network network, MailHandler mailHandler) { - this.dkg = dkg; - - this.g = dkg.getGenerator(); - this.group = dkg.getGroup(); - this.n = dkg.getN(); - this.t = dkg.getT(); - this.id = dkg.getId(); - - this.messageHandler = new MessageHandler(); - mailHandler.setMessageHandler(this.messageHandler); - this.user = network.connect(mailHandler,dkg.getId()); - this.parties = dkg.getParties(); - this.QUAL = null; - this.commitments = null; - this.share = null; - this.y = null; - } - - /** - * 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(user); - dkg.sendSecrets(user); - } - - - protected void waitUntilStageOneCompleted(){ - // all parties send their share or aborted - for (int i = 0 ; i < n ; i++){ - while (parties[i].share == null && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - // all parties broadcast their commitments or aborted - for (int i = 0 ; i < n ; i++){ - for (int k = 0 ; k <= t ; k++) { - while (parties[i].commitments[k] == null && !parties[i].aborted) { - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - } - - /** - * 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(user); - //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - user.broadcast(DKGMessages.Mail.Type.DONE,doneMessage); - } - - - protected void waitUntilStageTwoCompleted(){ - // all parties done or aborted - for (int i = 0 ; i < n ; i++){ - while (!parties[i].doneFlag && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - - /** - * 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(user); - // wait until there is no complaint waiting for answer - for (int i = 0; i < n; i++){ - for (int j = 0; j < n; j++){ - while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted){ - try { - Thread.sleep(SleepTime); - } catch (InterruptedException e) { - // do nothing - } - } - } - } - 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); - } - - protected void startReceiver(){ - user.getReceiverThread().start(); - } - protected void stopReceiver(){ - user.getReceiverThread().interrupt(); - } - - @Override - public void run() { - startReceiver(); - stage1(); - waitUntilStageOneCompleted(); - stage2(); - waitUntilStageTwoCompleted(); - stage3(); - stage4(); - stopReceiver(); - } - - /** - * Request the current run loop to exit gracefully - */ - public void stop() { - // TODO: implement - } - - @Override - public BigInteger[] getCommitments() { - return Arrays.copyOf(commitments, commitments.length); - } - - @Override - public BigInteger getGenerator() { - return g; - } - - @Override - public Group getGroup() { - return group; - } - - @Override - public Polynomial.Point getShare() { - return share; - } - - @Override - public int getID() { - return id; - } - - @Override - public int getN() { - return n; - } - - @Override - public int getT() { - return t; - } - - @Override - public BigInteger getPublicValue() { - return y; - } - - @Override - public Set getQUAL() { - return QUAL; - } - - - protected class MessageHandler implements Communication.MessageHandler{ - - /** - * 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, DKGMessages.CommitmentMessage commitmentMessage){ - int i = sender - 1; - int k = commitmentMessage.getK(); - return isBroadcast && parties[i].commitments[k] == null; - } - - /** - * saves the commitment - */ - @Override - public void handleCommitmentMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; - if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ - int i = sender - 1; - int k = commitmentMessage.getK(); - parties[i].commitments[k] = extractCommitment(commitmentMessage); - } - } - - /** - * 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, DKGMessages.SecretMessage secretMessage){ - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - if(sender != i || isBroadcast) - return false; - else - return parties[i - 1].share == null && j == id; - - } - - /** - * saves the secret - */ - @Override - public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; - if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - Polynomial.Point secret = extractSecret(id,secretMessage.getSecret()); - parties[i - 1].share = secret; - } - } - - /** - * 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; - } - - /** - * marks that the sender was finished sending all his complaints - */ - @Override - public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { - if(isValidDoneMessage(sender,isBroadcast)) { - parties[sender - 1].doneFlag = true; - } - } - - /** - * 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, DKGMessages.IDMessage complaintMessage){ - int i = sender; - int j = complaintMessage.getId(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.OK); - } - - /** - * marks that the sender was complained against id - */ - @Override - public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; - } - } - - /** - * 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, DKGMessages.SecretMessage 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(ComplaintState.Waiting); - } - - /** - * 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 - */ - @Override - public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.SecretMessage secretMessage = (DKGMessages.SecretMessage) message; - if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - Polynomial.Point secret = extractSecret(j,secretMessage.getSecret()); - if (dkg.isValidSecret(secret, parties[i - 1].commitments, j)) { - parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; - } else { - parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; - } - if(j == id){ - parties[i - 1].share = secret; - } - } - } - - /** - * marks that the sender was aborted - */ - @Override - public void handleAbortMessage(int sender, boolean isBroadcast, Message message) { - parties[sender - 1].aborted = true; - } - - public Polynomial.Point extractSecret(int i, ByteString secret){ - BigInteger x = BigInteger.valueOf(i); - BigInteger y = new BigInteger(secret.toByteArray()); - return new Polynomial.Point(x,y); - } - - public BigInteger extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ - return new BigInteger(commitmentMessage.getCommitment().toByteArray()); - } - } -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.utilitis.Channel; +import Communication.MailHandler; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; +import org.factcenter.qilin.primitives.Group; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Set; +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGeneration.ComplaintState; + +/** + * Created by Tzlil on 3/14/2016. + * TODO: Comments + * TODO: Replace polling with monitors/wait/notify (remember synchronization) + */ +public class User implements Runnable{ + + protected final DistributedKeyGeneration dkg; + + protected final T g; + protected final Group group; + protected final int n; + protected final int t; + protected final int id; + protected MailHandler mailHandler; + + protected final Channel channel; + protected final Party[] parties; + protected Set QUAL; // set of all non-disqualified parties + protected Polynomial.Point share; // final share of the secrete + protected ArrayList commitments; // public verification values + protected T y; // final public value + + public User(DistributedKeyGeneration 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; + + } + + /** + * create MailHandler and register it as ReceiverCallback + */ + protected void registerReceiverCallback(){ + this.mailHandler = new DistributedKeyGenerationMailHandler(new MessageHandler()); + channel.registerReceiverCallback(mailHandler); + } + + /** + * 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(); + } + + + protected void waitUntilStageOneCompleted(){ + // all parties send their share or aborted + for (int i = 0 ; i < n ; i++){ + synchronized (parties[i]) { + while (parties[i].share == null && !parties[i].aborted) { + try { + parties[i].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + // all parties broadcast their commitments or aborted + for (int i = 0 ; i < n ; i++){ + for (int k = 0 ; k <= t ; k++) { + synchronized (parties[i]) { + while (parties[i].commitments.get(k) == null && !parties[i].aborted) { + try { + parties[i].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + } + } + + /** + * 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 + DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); + channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); + } + + + protected void waitUntilStageTwoCompleted(){ + // all parties done or aborted + for (int i = 0 ; i < n ; i++){ + synchronized (parties[i]) { + while (!parties[i].doneFlag && !parties[i].aborted) { + try { + parties[i].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + } + + + /** + * 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 + for (int i = 0; i < n; i++){ + for (int j = 0; j < n; j++){ + synchronized (parties[i]) { + while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted) { + try { + parties[i].wait(); + } catch (InterruptedException e) { + //do nothing + } + } + } + } + } + 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() { + stage1(); + waitUntilStageOneCompleted(); + stage2(); + waitUntilStageTwoCompleted(); + stage3(); + stage4(); + } + + /** + * Request the current run loop to exit gracefully + */ + public void stop() { + + } + + /** + * getter + * @return commitments + */ + public ArrayList getCommitments() { + return commitments; + } + + /** + * getter + * @return g + */ + public T getGenerator() { + return g; + } + + /** + * getter + * @return group + */ + public Group 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 getQUAL() { + return QUAL; + } + + + public class MessageHandler implements Communication.MessageHandler{ + + public MessageHandler(){ + + } + /** + * 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, DKGMessages.CommitmentMessage commitmentMessage){ + int i = sender - 1; + int k = commitmentMessage.getK(); + return isBroadcast && parties[i].commitments.get(k) == null; + } + + /** + * saves the commitment + */ + @Override + public void handleCommitmentMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; + if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ + int i = sender - 1; + int k = commitmentMessage.getK(); + synchronized (parties[i]) { + parties[i].commitments.set(k, extractCommitment(commitmentMessage)); + parties[i].notify(); + } + } + } + + /** + * 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, DKGMessages.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; + + } + + /** + * saves the secret + */ + @Override + public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; + if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + Polynomial.Point secret = extractShare(id,secretMessage.getSecret()); + synchronized (parties[i -1]) { + parties[i - 1].share = secret; + parties[i - 1].notify(); + } + } + } + + /** + * 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; + } + + /** + * marks that the sender was finished sending all his complaints + */ + @Override + public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { + if(isValidDoneMessage(sender,isBroadcast)) { + synchronized (parties[sender - 1]) { + parties[sender - 1].doneFlag = true; + parties[sender - 1].notify(); + } + } + } + + /** + * 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, DKGMessages.IDMessage complaintMessage){ + int i = sender; + int j = complaintMessage.getId(); + return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.OK); + } + + /** + * marks that the sender was complained against id + */ + @Override + public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + synchronized (parties[j - 1]) { + parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; + parties[j - 1].notify(); + } + } + } + + /** + * 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, DKGMessages.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(ComplaintState.Waiting); + } + + /** + * 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 + */ + @Override + public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { + DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; + if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + Polynomial.Point secret = extractShare(j,secretMessage.getSecret()); + synchronized (parties[i - 1]) { + if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) { + parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; + } else { + parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; + } + if (j == id) { + parties[i - 1].share = secret; + } + parties[i - 1].notify(); + } + } + } + + /** + * marks that the sender was aborted + */ + @Override + public void handleAbortMessage(int sender, boolean isBroadcast, Message message) { + synchronized (parties[sender - 1]) { + parties[sender - 1].aborted = true; + parties[sender - 1].notify(); + } + } + + /** + * 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(DKGMessages.CommitmentMessage commitmentMessage){ + return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray()); + } + } +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java new file mode 100644 index 0000000..a15f0e2 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java @@ -0,0 +1,108 @@ +package meerkat.crypto.concrete.secret_shring.feldman_verifiable; + +import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.Polynomial; +import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.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 extends SecretSharing { + protected final Group group; + protected final T g; // public generator of group + protected final ArrayList 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 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 generateCommitments() { + + Polynomial polynomial = getPolynomial(); + BigInteger[] coefficients = polynomial.getCoefficients(); + ArrayList commitments = new ArrayList(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 computeVerificationValue(int j, ArrayList commitments, Group 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 getGroup(){ + return group; + } + + /** + * getter + * @return commitmentsArrayList + */ + public ArrayList getCommitmentsArrayList() { + return commitmentsArrayList; + } + +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java similarity index 94% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java index c3fb319..20aee54 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java @@ -1,66 +1,66 @@ -package ShamirSecretSharing; - -import Arithmetics.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 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; - } -} +package meerkat.crypto.concrete.secret_shring.shamir; + +import meerkat.crypto.utilitis.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 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; + } +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java similarity index 94% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java index 03c8f99..c2d77ff 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java @@ -1,208 +1,208 @@ -package ShamirSecretSharing; - -import Arithmetics.Arithmetic; - -import java.math.BigInteger; -import java.util.Arrays; - -/** - * Created by Tzlil on 1/27/2016. - */ -public class Polynomial implements Comparable { - private final int degree; - private final BigInteger[] coefficients; - private final Arithmetic arithmetic; - - /** - * constructor - * @param coefficients - * @param arithmetic - * degree set as max index such that coefficients[degree] not equals zero - */ - public Polynomial(BigInteger[] coefficients,Arithmetic 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 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 ShamirSecretSharing.PolynomialTests of degree max(this degree,other degree) s.t for all x in Z - * 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 in Z - * 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 in Z - * 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); - } - } - -} +package meerkat.crypto.concrete.secret_shring.shamir; + +import meerkat.crypto.utilitis.Arithmetic; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Created by Tzlil on 1/27/2016. + */ +public class Polynomial implements Comparable { + private final int degree; + private final BigInteger[] coefficients; + private final Arithmetic arithmetic; + + /** + * constructor + * @param coefficients + * @param arithmetic + * degree set as max index such that coefficients[degree] not equals zero + */ + public Polynomial(BigInteger[] coefficients,Arithmetic 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 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 meerkat.crypto.concrete.secret_shring.shamir.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); + } + } + +} diff --git a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java similarity index 84% rename from destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java rename to destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java index b9c0386..87853d5 100644 --- a/destributed-key-generation/src/main/java/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java @@ -1,111 +1,111 @@ -package ShamirSecretSharing; - -import Arithmetics.Arithmetic; -import Arithmetics.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{ - protected final int t; - protected final int n; - protected final BigInteger q; - 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 x secret, chosen from Zq - * @param random use for generate random polynomial - */ - public SecretSharing(int t, int n, BigInteger x, Random random, BigInteger q) { - this.q = q; - this.t = t; - this.n = n; - this.polynomial = generateRandomPolynomial(x,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)%q - */ - 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 arithmetic) throws Exception { - 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 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; - } -} +package meerkat.crypto.concrete.secret_shring.shamir; + +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.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{ + protected final int t; + protected final int n; + protected final BigInteger q; + 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 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 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; + } +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java similarity index 85% rename from destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java rename to destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java index 979ea60..618210a 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Arithmetic.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java @@ -1,18 +1,18 @@ -package Arithmetics; - -/** - * Created by Tzlil on 3/17/2016. - */ -public interface Arithmetic { - /** - * - * @param a - * @param b - * @return - */ - T add(T a, T b); - T sub(T a, T b); - T mul(T a, T b); - T div(T a, T b); - -} +package meerkat.crypto.utilitis; + +/** + * Created by Tzlil on 3/17/2016. + */ +public interface Arithmetic { + /** + * + * @param a + * @param b + * @return + */ + T add(T a, T b); + T sub(T a, T b); + T mul(T a, T b); + T div(T a, T b); + +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java new file mode 100644 index 0000000..2be0bf4 --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java @@ -0,0 +1,26 @@ +package meerkat.crypto.utilitis; + +import com.google.protobuf.Message; +import meerkat.protobuf.DKGMessages; + +/** + * A generic commmunication channel that supports point-to-point and broadcast operation + */ + +public interface Channel { + public interface ReceiverCallback { + public void receiveMail(DKGMessages.Mail mail); + } + + public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg); + + public void broadcastMessage(DKGMessages.Mail.Type type, Message msg); + + /** + * Register a callback to handle received messages. + * The callback is called in the Channel thread, so no long processing should + * occur in the callback method. + * @param callback + */ + public void registerReceiverCallback(ReceiverCallback callback); +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Fp.java b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java similarity index 90% rename from destributed-key-generation/src/main/java/Arithmetics/Fp.java rename to destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java index 0525d08..e538293 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Fp.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java @@ -1,38 +1,39 @@ -package Arithmetics; - -import org.factcenter.qilin.primitives.concrete.Zpstar; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/17/2016. - */ -public class Fp implements Arithmetic { - public final BigInteger p; - private final Zpstar zp; - - 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)); - } -} +package meerkat.crypto.utilitis.concrete; + +import meerkat.crypto.utilitis.Arithmetic; +import org.factcenter.qilin.primitives.concrete.Zpstar; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 3/17/2016. + */ +public class Fp implements Arithmetic { + public final BigInteger p; + private final Zpstar zp; + + 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)); + } +} diff --git a/destributed-key-generation/src/test/java/Utils/ChannelImpl.java b/destributed-key-generation/src/test/java/Utils/ChannelImpl.java new file mode 100644 index 0000000..31bf748 --- /dev/null +++ b/destributed-key-generation/src/test/java/Utils/ChannelImpl.java @@ -0,0 +1,108 @@ +package Utils; + +import com.google.protobuf.Message; +import meerkat.crypto.utilitis.Channel; +import meerkat.protobuf.DKGMessages; + +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +/** + * Created by Tzlil on 2/14/2016. + */ +// TODO: Change nane to network + +public class ChannelImpl implements Channel { + + public static int BROADCAST = 0; + private static ChannelImpl[] channels = null; + + protected final Queue mailbox; + protected final int id; + protected final int n; + protected Thread receiverThread; + + + public ChannelImpl(int id, int n) { + if (channels == null){ + channels = new ChannelImpl[n]; + } + this.mailbox = new ArrayBlockingQueue( n * n * n); + this.id = id; + this.n = n; + channels[id - 1] = this; + } + + public int getId() { + return id; + } + + @Override + public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg) { + if(destUser < 1 || destUser > n) + return; + ChannelImpl channel = channels[destUser - 1]; + if (channel == null) + return; + DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + .setSender(id) + .setDestination(destUser) + .setIsPrivate(true) + .setType(type) + .setMessage(msg.toByteString()) + .build(); + synchronized (channel.mailbox) { + channel.mailbox.add(mail); + channel.mailbox.notify(); + } + } + + @Override + public void broadcastMessage(DKGMessages.Mail.Type type,Message msg) { + ChannelImpl channel; + DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + .setSender(id) + .setDestination(BROADCAST) + .setIsPrivate(false) + .setType(type) + .setMessage(msg.toByteString()) + .build(); + for (int i = 0 ; i < n ; i++){ + channel = channels[i]; + synchronized (channel.mailbox) { + channel.mailbox.add(mail); + channel.mailbox.notify(); + } + } + } + + @Override + public void registerReceiverCallback(final ReceiverCallback callback) { + try{ + receiverThread.interrupt(); + }catch (Exception e){ + //do nothing + } + receiverThread = new Thread(new Runnable() { + @Override + public void run() { + while (true){ + try { + synchronized (mailbox) { + while (!mailbox.isEmpty()) { + callback.receiveMail(mailbox.remove()); + } + mailbox.wait(); + } + } catch (InterruptedException e) { + //do nothing + } + } + } + }); + receiverThread.start(); + } + + + +} diff --git a/destributed-key-generation/src/main/java/Arithmetics/Z.java b/destributed-key-generation/src/test/java/Utils/Z.java similarity index 84% rename from destributed-key-generation/src/main/java/Arithmetics/Z.java rename to destributed-key-generation/src/test/java/Utils/Z.java index acf486d..4f69fa4 100644 --- a/destributed-key-generation/src/main/java/Arithmetics/Z.java +++ b/destributed-key-generation/src/test/java/Utils/Z.java @@ -1,29 +1,30 @@ -package Arithmetics; - -import java.math.BigInteger; - -/** - * Created by Tzlil on 3/17/2016. - */ -public class Z implements Arithmetic { - - @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); - } -} +package Utils; + +import meerkat.crypto.utilitis.Arithmetic; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 4/8/2016. + */ +public class Z implements Arithmetic { + @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); + } +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java similarity index 53% rename from destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java index a0c1d4e..e4adfc6 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java @@ -1,61 +1,62 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.Network; -import JointFeldmanProtocol.DistributedKeyGeneration; - -import java.math.BigInteger; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/29/2016. - */ -public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUserImpl { - - private final DistributedKeyGeneration maliciousSDKG; - private final Set falls; - public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg,SecureDistributedKeyGeneration maliciousSDKG - , Network network,Set falls) { - super(sdkg, network); - this.falls = falls; - this.maliciousSDKG = maliciousSDKG; - maliciousSDKG.setParties(parties); - } - - public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Random random){ - BigInteger q = sdkg.getQ(); - BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - return new SecureDistributedKeyGeneration(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() - ,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId()); - } - - @Override - public void stage1() { - sdkg.broadcastVerificationValues(user); - sendSecrets(); //insteadof dkg.sendSecrets(user); - } - - @Override - public void stage3() { - stopReceiver(); - maliciousSDKG.answerAllComplainingPlayers(user); - } - - @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(user,j); - }else { - sdkg.sendSecret(user, j); - } - } - } - } - -} +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.utilitis.Channel; +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGeneration; + +import java.math.BigInteger; +import java.util.Random; +import java.util.Set; + +/** + * Created by Tzlil on 3/29/2016. + */ +public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUser { + + private final DistributedKeyGeneration maliciousSDKG; + private final Set falls; + public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg, SecureDistributedKeyGeneration maliciousSDKG + , Channel channel, Set falls) { + super(sdkg, channel); + this.falls = falls; + this.maliciousSDKG = maliciousSDKG; + maliciousSDKG.setParties(parties); + } + + public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Channel channel,Random random){ + BigInteger q = sdkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + SecureDistributedKeyGeneration malicious = new SecureDistributedKeyGeneration(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 dkg.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); + } + } + } + } + +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java similarity index 77% rename from destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java index 647e4cf..6e44252 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java @@ -1,177 +1,181 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import JointFeldmanProtocol.DKGMaliciousUserImpl; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import UserInterface.DistributedKeyGenerationUser; -import Utils.GenerateRandomPrime; -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.HashSet; -import java.util.Random; -import java.util.Set; - -/** - * Created by Tzlil on 3/29/2016. - */ -public class SDKGTest { - - int tests = 10; - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - Group group = new Zpstar(p); - Arithmetic arithmetic = new Fp(q); - int t = 9; - int n = 20; - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; - 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.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 sharesList = new ArrayList(); - - 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 { - for (int i = 0; i < tests; i++){ - oneTest(i); - } - } - - class Testable{ - Set valids; - Set QUAL; - Set aborted; - Set malicious; - DistributedKeyGenerationUser[] sdkgs; - Thread[] threads; - BigInteger g; - BigInteger h; - BigInteger secret; - - public Testable(Random random) { - this.sdkgs = new SecureDistributedKeyGenerationUserImpl[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); - this.threads = new Thread[n]; - this.g = sampleGenerator(random); - this.h = group.multiply(g,randomIntModQ(random)); - ArrayList ids = new ArrayList(); - for (int id = 1; id<= n ; id++){ - ids.add(id); - } - Network network = new Network(n); - int id; - BigInteger s; - SecureDistributedKeyGeneration sdkg; - this.secret = BigInteger.ZERO; - while (!ids.isEmpty()) { - id = ids.remove(random.nextInt(ids.size())); - s = randomIntModQ(random); - sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id); - sdkgs[id - 1] = randomSDKGUser(id,network,sdkg,random); - threads[id - 1] = new Thread(sdkgs[id - 1]); - if(QUAL.contains(id)){ - this.secret = this.secret.add(s).mod(q); - } - } - - } - - public SecureDistributedKeyGenerationUserImpl randomSDKGUser(int id,Network network, SecureDistributedKeyGeneration sdkg,Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new SecureDistributedKeyGenerationUserImpl(sdkg,network); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); - QUAL.add(id); - return new SecureDistributedKeyGenerationUserImpl(sdkg,network); - case 1:// abort - int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 - aborted.add(id); - if (abortStage > 1){ - QUAL.add(id); - } - return new SDKGUserImplAbort(sdkg,network,abortStage); - case 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); - SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,network,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); - } - - } -} +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.concrete.Fp; +import meerkat.crypto.utilitis.Channel; +import Communication.ChannelImpl; +import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; +import Utils.BigIntegerByteEncoder; +import Utils.GenerateRandomPrime; +import org.factcenter.qilin.primitives.Group; +import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.factcenter.qilin.util.ByteEncoder; +import org.junit.Before; +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/29/2016. + */ +public class SDKGTest { + + int tests = 1; + BigInteger p = GenerateRandomPrime.SafePrime100Bits; + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + Testable[] testables; + + @Before + public void settings(){ + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); + } + } + + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + 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.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 sharesList = new ArrayList(); + + 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 { + for (int i = 0; i < tests; i++){ + oneTest(i); + } + } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + SecureDistributedKeyGenerationUser[] sdkgs; + Thread[] threads; + BigInteger g; + BigInteger h; + BigInteger secret; + + public Testable(Random random) { + this.sdkgs = new SecureDistributedKeyGenerationUser[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + this.h = group.multiply(g,randomIntModQ(random)); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + int id; + BigInteger s; + Channel channel; + SecureDistributedKeyGeneration sdkg; + this.secret = BigInteger.ZERO; + ByteEncoder encoder = new BigIntegerByteEncoder(); + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + s = randomIntModQ(random); + channel = new ChannelImpl(id,n); + sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id,encoder); + sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg,random); + threads[id - 1] = new Thread(sdkgs[id - 1]); + if(QUAL.contains(id)){ + this.secret = this.secret.add(s).mod(q); + } + } + + } + + public SecureDistributedKeyGenerationUser randomSDKGUser(int id, Channel channel, SecureDistributedKeyGeneration sdkg, Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUser(sdkg,channel); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new SecureDistributedKeyGenerationUser(sdkg,channel); + case 1:// abort + 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 2:// malicious + malicious.add(id); + Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); + SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); + return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,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); + } + + } +} diff --git a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java similarity index 66% rename from destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java index 551de93..2690048 100644 --- a/destributed-key-generation/src/test/java/SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java @@ -1,65 +1,63 @@ -package SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem; - -import Communication.Network; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGeneration; -import SecureDistributedKeyGenerationForDiscreteLogBasedCryptosystem.SecureDistributedKeyGenerationUserImpl; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUserImpl { - - final int abortStage; - int stage; - public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Network network, int abortStage) { - super(sdkg, network); - this.abortStage = abortStage;// 1 - 4 - this.stage = 1; - } - - private void abort(){ - stopReceiver(); - user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); - } - - @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++; - } -} +package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; + +import meerkat.crypto.utilitis.Channel; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUser { + + final int abortStage; + int stage; + public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Channel channel, int abortStage) { + super(sdkg, channel); + this.abortStage = abortStage;// 1 - 4 + this.stage = 1; + } + + private void abort(){ + //stopReceiver(); + channel.broadcastMessage(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java similarity index 59% rename from destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java index 4dfd4a4..2c7bea2 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java @@ -1,72 +1,73 @@ -package JointFeldmanProtocol; - -import Communication.MailHandler; -import Communication.Network; - -import java.math.BigInteger; -import java.util.*; - -/** - * Created by Tzlil on 3/21/2016. - */ -public class DKGMaliciousUserImpl extends DistributedKeyGenerationUserImpl { - - private final DistributedKeyGeneration maliciousDkg; - private final Set falls; - public DKGMaliciousUserImpl(DistributedKeyGeneration dkg,DistributedKeyGeneration maliciousDKG, Network network,Set falls) { - super(dkg, network); - this.falls = falls; - this.maliciousDkg = maliciousDKG; - maliciousDKG.setParties(parties); - } - - public static Set selectFallsRandomly(Set ids, Random random){ - Set falls = new HashSet(); - ArrayList idsList = new ArrayList(); - 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 DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Random random){ - BigInteger q = dkg.getQ(); - BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - return new DistributedKeyGeneration(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() - ,dkg.getGenerator(),dkg.getGroup(),dkg.getId()); - } - - @Override - public void stage1() { - dkg.broadcastCommitments(user); - sendSecrets(); //insteadof dkg.sendSecrets(user); - } - - @Override - public void stage3() { - maliciousDkg.answerAllComplainingPlayers(user); - } - - @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(user,j); - }else { - dkg.sendSecret(user, j); - } - } - } - } - - -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.utilitis.Channel; + +import java.math.BigInteger; +import java.util.*; + +/** + * Created by Tzlil on 3/21/2016. + */ +public class DKGMaliciousUser extends DistributedKeyGenerationUser { + + private final DistributedKeyGeneration maliciousDkg; + private final Set falls; + public DKGMaliciousUser(DistributedKeyGeneration dkg, DistributedKeyGeneration maliciousDKG, Channel channel, Set falls) { + super(dkg, channel); + this.falls = falls; + this.maliciousDkg = maliciousDKG; + maliciousDKG.setParties(parties); + } + + public static Set selectFallsRandomly(Set ids, Random random){ + Set falls = new HashSet(); + ArrayList idsList = new ArrayList(); + 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 DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Channel channel,Random random){ + BigInteger q = dkg.getQ(); + BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); + DistributedKeyGeneration malicious = new DistributedKeyGeneration(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 dkg.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); + } + } + } + } + + +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java similarity index 78% rename from destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java index 7599a53..f4b2780 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java @@ -1,175 +1,179 @@ -package JointFeldmanProtocol; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Communication.Network; -import FeldmanVerifiableSecretSharing.VerifiableSecretSharing; -import ShamirSecretSharing.Polynomial; -import ShamirSecretSharing.SecretSharing; -import UserInterface.DistributedKeyGenerationUser; -import Utils.GenerateRandomPrime; -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.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 group = new Zpstar(p); - Arithmetic arithmetic = new Fp(q); - int t = 9; - int n = 20; - - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; - 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 sharesList = new ArrayList(); - - 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 { - for (int i = 0; i < tests; i++){ - oneTest(i); - } - } - - class Testable{ - Set valids; - Set QUAL; - Set aborted; - Set malicious; - DistributedKeyGenerationUser[] dkgs; - Thread[] threads; - BigInteger g; - BigInteger secret; - - public Testable(Random random) { - this.dkgs = new DistributedKeyGenerationUserImpl[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); - this.threads = new Thread[n]; - this.g = sampleGenerator(random); - ArrayList ids = new ArrayList(); - for (int id = 1; id<= n ; id++){ - ids.add(id); - } - Network network = new Network(n); - int id; - BigInteger s; - DistributedKeyGeneration dkg; - this.secret = BigInteger.ZERO; - while (!ids.isEmpty()) { - id = ids.remove(random.nextInt(ids.size())); - s = randomIntModQ(random); - dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id); - dkgs[id - 1] = randomDKGUser(id,network,dkg,random); - threads[id - 1] = new Thread(dkgs[id - 1]); - if(QUAL.contains(id)){ - this.secret = this.secret.add(s).mod(q); - } - } - - } - - public DistributedKeyGenerationUser randomDKGUser(int id,Network network, DistributedKeyGeneration dkg,Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); - QUAL.add(id); - return new DistributedKeyGenerationUserImpl(dkg,network); - 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,network,abortStage); - case 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUserImpl.selectFallsRandomly(valids,random); - DistributedKeyGeneration maliciousDKG = DKGMaliciousUserImpl.generateMaliciousDKG(dkg,random); - return new DKGMaliciousUserImpl(dkg,maliciousDKG,network,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); - } - - } -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.concrete.Fp; +import meerkat.crypto.utilitis.Channel; +import Communication.ChannelImpl; +import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; +import Utils.BigIntegerByteEncoder; +import Utils.GenerateRandomPrime; +import org.factcenter.qilin.primitives.Group; +import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.factcenter.qilin.util.ByteEncoder; +import org.junit.Before; +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 = 1; + BigInteger p = GenerateRandomPrime.SafePrime100Bits; + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + Group group = new Zpstar(p); + Arithmetic arithmetic = new Fp(q); + int t = 9; + int n = 20; + + Testable[] testables; + + @Before + public void settings(){ + testables = new Testable[tests]; + for (int i = 0; i < tests; i++){ + testables[i] = new Testable(new Random()); + } + } + + public void oneTest(int test) throws Exception { + Testable testable = testables[test]; + 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 sharesList = new ArrayList(); + + 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 { + for (int i = 0; i < tests; i++){ + oneTest(i); + } + } + + class Testable{ + Set valids; + Set QUAL; + Set aborted; + Set malicious; + DistributedKeyGenerationUser[] dkgs; + Thread[] threads; + BigInteger g; + BigInteger secret; + + public Testable(Random random) { + this.dkgs = new DistributedKeyGenerationUser[n]; + this.valids = new HashSet(); + this.QUAL = new HashSet(); + this.aborted = new HashSet(); + this.malicious = new HashSet(); + this.threads = new Thread[n]; + this.g = sampleGenerator(random); + ArrayList ids = new ArrayList(); + for (int id = 1; id<= n ; id++){ + ids.add(id); + } + int id; + BigInteger s; + DistributedKeyGeneration dkg; + this.secret = BigInteger.ZERO; + Channel channel; + ByteEncoder byteEncoder = new BigIntegerByteEncoder(); + while (!ids.isEmpty()) { + id = ids.remove(random.nextInt(ids.size())); + channel = new ChannelImpl(id,n); + s = randomIntModQ(random); + dkg = new DistributedKeyGeneration(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 DistributedKeyGenerationUser randomDKGUser(int id, Channel channel, DistributedKeyGeneration dkg, Random random){ + if (QUAL.size() <= t) { + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUser(dkg,channel); + }else{ + int type = random.nextInt(3); + switch (type){ + case 0:// regular + valids.add(id); + QUAL.add(id); + return new DistributedKeyGenerationUser(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 falls = DKGMaliciousUser.selectFallsRandomly(valids,random); + DistributedKeyGeneration 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); + } + + } +} diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java similarity index 75% rename from destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java index 6acb8ce..88a0847 100644 --- a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java @@ -1,63 +1,63 @@ -package JointFeldmanProtocol; - -import Communication.Network; -import meerkat.protobuf.DKGMessages; - -/** - * Created by Tzlil on 3/14/2016. - */ -public class DKGUserImplAbort extends DistributedKeyGenerationUserImpl { - - final int abortStage; - int stage; - public DKGUserImplAbort(DistributedKeyGeneration dkg, Network network, int abortStage) { - super(dkg, network); - this.abortStage = abortStage;// 1 - 2 - this.stage = 1; - } - - - private void sendAbort(){ - user.broadcast(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); - } - - @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++; - } -} +package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; + +import meerkat.crypto.utilitis.Channel; +import meerkat.protobuf.DKGMessages; + +/** + * Created by Tzlil on 3/14/2016. + */ +public class DKGUserImplAbort extends DistributedKeyGenerationUser { + + final int abortStage; + int stage; + public DKGUserImplAbort(DistributedKeyGeneration dkg, Channel channel, int abortStage) { + super(dkg, channel); + this.abortStage = abortStage;// 1 - 2 + this.stage = 1; + } + + + private void sendAbort(){ + channel.broadcastMessage(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + } + + @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++; + } +} diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java similarity index 85% rename from destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java index 897957e..f7d3a39 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java @@ -1,67 +1,68 @@ -package FeldmanVerifiableSecretSharing; - -import ShamirSecretSharing.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.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 verifiableSecretSharing) throws Exception { - int n = verifiableSecretSharing.getN(); - Group zpstar = verifiableSecretSharing.getGroup(); - BigInteger g = verifiableSecretSharing.getGenerator(); - Polynomial.Point[] shares = new Polynomial.Point[n]; - BigInteger[] commitments = verifiableSecretSharing.getCommitmentsArray(); - 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]); - } - } -} +package meerkat.crypto.concrete.secret_shring.feldman_verifiable; + +import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.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 verifiableSecretSharing) throws Exception { + int n = verifiableSecretSharing.getN(); + Group zpstar = verifiableSecretSharing.getGroup(); + BigInteger g = verifiableSecretSharing.getGenerator(); + Polynomial.Point[] shares = new Polynomial.Point[n]; + ArrayList 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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java similarity index 89% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java index a95552d..2c78b03 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java @@ -1,46 +1,46 @@ -package ShamirSecretSharing.PolynomialTests; -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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]); - } - } -} +package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import meerkat.crypto.concrete.secret_shring.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java similarity index 89% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java index a222b95..0183d3f 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java @@ -1,68 +1,68 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.Polynomial; -import 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 arithmetic; - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - - @Before - public void settings(){ - random = new Random(); - polynomials = new Polynomial[tests]; - pointsArrays = new Polynomial.Point[tests][]; - for (int i = 0; i < polynomials.length; i++){ - polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p); - pointsArrays[i] = randomPoints(polynomials[i]); - } - arithmetic = new Fp(p); - } - - public Polynomial.Point[] randomPoints(Polynomial polynomial){ - Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1]; - BigInteger x; - Set 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]); - } - } -} +package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; + +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.concrete.Fp; +import Utils.GenerateRandomPolynomial; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import 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 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 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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java similarity index 89% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java index 2f073c5..30e2082 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java @@ -1,48 +1,48 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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]); - } - } -} +package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; + +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import meerkat.crypto.concrete.secret_shring.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java similarity index 89% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java index 478e541..8af27ab 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java @@ -1,48 +1,48 @@ -package ShamirSecretSharing.PolynomialTests; - -import Arithmetics.Z; -import Utils.GenerateRandomPolynomial; -import ShamirSecretSharing.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]); - } - } -} +package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; + +import Arithmetics.Z; +import Utils.GenerateRandomPolynomial; +import meerkat.crypto.concrete.secret_shring.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]); + } + } +} diff --git a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java similarity index 81% rename from destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java rename to destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java index 40cf306..0396916 100644 --- a/destributed-key-generation/src/test/java/ShamirSecretSharing/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java @@ -1,63 +1,64 @@ -package ShamirSecretSharing; - -import Arithmetics.Z; -import 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 group; - int tests = 1 << 10; - Random random; - - @Before - public void settings(){ - BigInteger p = GenerateRandomPrime.SafePrime100Bits; - BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); - group = new Zn(p); - 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 indexes = new ArrayList(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()))); - } - assert(secret.equals(SecretSharing.recoverSecret(shares,new Z()))); - } - - @Test - public void secretSharingTest() throws Exception { - for (int i = 0 ; i < secretSharingArray.length; i ++){ - oneTest(secretSharingArray[i],secrets[i]); - } - } -} +package meerkat.crypto.concrete.secret_shring.shamir; + +import meerkat.crypto.utilitis.concrete.Fp; +import 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 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 indexes = new ArrayList(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]); + } + } +} From 5d564c834c5b51970c82bda8f74573c4dce19995 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 8 Apr 2016 15:04:07 +0300 Subject: [PATCH 037/106] generic group + wait instead of sleep --- .../java/Utils/BigIntegerByteEncoder.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java diff --git a/destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java b/destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java new file mode 100644 index 0000000..a0c7107 --- /dev/null +++ b/destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java @@ -0,0 +1,28 @@ +package Utils; + +import java.math.BigInteger; + +/** + * Created by Tzlil on 4/7/2016. + */ +public class BigIntegerByteEncoder implements org.factcenter.qilin.util.ByteEncoder { + @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); + } +} From 3e1f59ec2b58c32aefd70da7aeedbba620e7c968 Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 8 Apr 2016 15:46:54 +0300 Subject: [PATCH 038/106] switch secret with share --- .../Communication/ChannelImpl.java | 108 ------------------ .../Communication/MailHandler.java | 26 ++--- .../Communication/MessageHandler.java | 2 +- .../gjkr_secure_protocol/MailHandler.java | 5 +- .../gjkr_secure_protocol/Party.java | 3 +- .../gjkr_secure_protocol/Protocol.java | 5 +- .../gjkr_secure_protocol/User.java | 19 ++- .../joint_feldman_protocol/MailHandler.java | 5 +- .../joint_feldman_protocol/Party.java | 7 +- .../joint_feldman_protocol/Protocol.java | 4 +- .../joint_feldman_protocol/User.java | 28 +++-- .../VerifiableSecretSharing.java | 5 +- .../java/Utils/GenerateRandomPolynomial.java | 8 +- .../SDKGMaliciousUserImpl.java | 12 +- .../gjkr_secure_protocol/SDKGTest.java | 18 +-- .../SDKGUserImplAbort.java | 4 +- .../DKGMaliciousUser.java | 10 +- .../joint_feldman_protocol/DKGTest.java | 19 +-- .../DKGUserImplAbort.java | 4 +- .../VerifiableSecretSharingTest.java | 2 +- .../shamir/PolynomialTests/AddTest.java | 2 +- .../PolynomialTests/MulByConstTest.java | 2 +- .../shamir/PolynomialTests/MulTest.java | 2 +- .../src/main/proto/meerkat/DKGMessages.proto | 12 +- 24 files changed, 98 insertions(+), 214 deletions(-) delete mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java deleted file mode 100644 index 04fa4ef..0000000 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/ChannelImpl.java +++ /dev/null @@ -1,108 +0,0 @@ -package meerkat.crypto.concrete.distributed_key_generation.Communication; - -import com.google.protobuf.Message; -import meerkat.crypto.utilitis.Channel; -import meerkat.protobuf.DKGMessages; - -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Created by Tzlil on 2/14/2016. - */ -// TODO: Change nane to network - -public class ChannelImpl implements Channel { - - public static int BROADCAST = 0; - private static ChannelImpl[] channels = null; - - protected final Queue mailbox; - protected final int id; - protected final int n; - protected Thread receiverThread; - - - public ChannelImpl(int id, int n) { - if (channels == null){ - channels = new ChannelImpl[n]; - } - this.mailbox = new ArrayBlockingQueue( n * n * n); - this.id = id; - this.n = n; - channels[id - 1] = this; - } - - public int getId() { - return id; - } - - @Override - public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg) { - if(destUser < 1 || destUser > n) - return; - ChannelImpl channel = channels[destUser - 1]; - if (channel == null) - return; - DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() - .setSender(id) - .setDestination(destUser) - .setIsPrivate(true) - .setType(type) - .setMessage(msg.toByteString()) - .build(); - synchronized (channel.mailbox) { - channel.mailbox.add(mail); - channel.mailbox.notify(); - } - } - - @Override - public void broadcastMessage(DKGMessages.Mail.Type type,Message msg) { - ChannelImpl channel; - DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() - .setSender(id) - .setDestination(BROADCAST) - .setIsPrivate(false) - .setType(type) - .setMessage(msg.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - channel = channels[i]; - synchronized (channel.mailbox) { - channel.mailbox.add(mail); - channel.mailbox.notify(); - } - } - } - - @Override - public void registerReceiverCallback(final ReceiverCallback callback) { - try{ - receiverThread.interrupt(); - }catch (Exception e){ - //do nothing - } - receiverThread = new Thread(new Runnable() { - @Override - public void run() { - while (true){ - try { - synchronized (mailbox) { - while (!mailbox.isEmpty()) { - callback.receiveMail(mailbox.remove()); - } - mailbox.wait(); - } - } catch (InterruptedException e) { - //do nothing - } - } - } - }); - receiverThread.start(); - } - - - -} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java index b01801f..c646a5a 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java @@ -1,4 +1,4 @@ -package meerkat.crypto.concrete.distributed_key_generation.Communication; +package meerkat.crypto.concrete.distributed_key_generation.communication; import com.google.protobuf.Message; import meerkat.crypto.utilitis.Channel; @@ -9,13 +9,19 @@ import meerkat.protobuf.DKGMessages; */ public abstract class MailHandler implements Channel.ReceiverCallback{ + public static final int BROADCAST = 0; private MessageHandler messageHandler; + public MailHandler(MessageHandler messageHandler){ this.messageHandler = messageHandler; } public abstract Message extractMessage(DKGMessages.Mail mail); + public boolean isBroadcast(DKGMessages.Mail mail){ + return mail.getDestination() == BROADCAST; + } + public void receiveMail(DKGMessages.Mail mail){ Message message = extractMessage(mail); @@ -24,28 +30,22 @@ public abstract class MailHandler implements Channel.ReceiverCallback{ switch (mail.getType()) { case SHARE: - messageHandler.handleSecretMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleSecretMessage(mail.getSender(), isBroadcast(mail),message); break; case COMMITMENT: - messageHandler.handleCommitmentMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleCommitmentMessage(mail.getSender(), isBroadcast(mail),message); break; case DONE: - messageHandler.handleDoneMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleDoneMessage(mail.getSender(), isBroadcast(mail),message); break; case COMPLAINT: - messageHandler.handleComplaintMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleComplaintMessage(mail.getSender(), isBroadcast(mail),message); break; case ANSWER: - messageHandler.handleAnswerMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleAnswerMessage(mail.getSender(), isBroadcast(mail),message); break; case ABORT: - messageHandler.handleAbortMessage(mail.getSender(), mail.getDestination() == ChannelImpl.BROADCAST - , message); + messageHandler.handleAbortMessage(mail.getSender(), isBroadcast(mail),message); break; default: break; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java index 74b453a..a58cbcc 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java @@ -1,4 +1,4 @@ -package meerkat.crypto.concrete.distributed_key_generation.Communication; +package meerkat.crypto.concrete.distributed_key_generation.communication; import com.google.protobuf.Message; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java index 4683f04..c35fe6c 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java @@ -1,15 +1,14 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; -import Communication.MailHandler; -import Communication.MessageHandler; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; +import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. */ -public class MailHandler extends Communication.MailHandler { +public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler { private boolean isStage4; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java index 82ebba8..c0ee63a 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java @@ -1,6 +1,5 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGenerationParty; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import java.util.ArrayList; @@ -14,7 +13,7 @@ import java.util.Set; * contains all relevant information on specific party during * the run of the safe protocol */ -public class Party extends DistributedKeyGenerationParty { +public class Party extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Party { public Polynomial.Point shareT; public boolean ysDoneFlag; public ArrayList verifiableValues; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java index db0cc56..13ff0e6 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java @@ -1,7 +1,6 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; @@ -137,8 +136,8 @@ public class Protocol extends meerkat.crypto.concrete.distributed_key_generat DKGMessages.DoubleShareMessage doubleShareMessage = DKGMessages.DoubleShareMessage.newBuilder() .setI(i) .setJ(j) - .setSecret(ByteString.copyFrom(share.y.toByteArray())) - .setSecretT(ByteString.copyFrom(shareT.y.toByteArray())) + .setShare(ByteString.copyFrom(share.y.toByteArray())) + .setShareT(ByteString.copyFrom(shareT.y.toByteArray())) .build(); return doubleShareMessage; } diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java index ac99b6e..f976ff9 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java @@ -3,7 +3,6 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; import meerkat.crypto.utilitis.Arithmetic; import meerkat.crypto.utilitis.concrete.Fp; import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; import com.google.protobuf.Message; @@ -22,7 +21,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. private Arithmetic arithmetic; private boolean isStage4; - public User(Protocol sdkg, Channel channel) { + public User(Protocol sdkg, Channel channel) { super(sdkg, channel); this.sdkg = sdkg; this.parties = sdkg.getParties(); @@ -176,7 +175,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() .setI(doubleSecretMessage.getI()) .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) + .setShare(doubleSecretMessage.getShare()) .build(); return super.isValidSecretMessage(sender,isBroadcast,secretMessage); } @@ -190,8 +189,8 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); synchronized (parties[i - 1]) { - parties[i - 1].share = extractShare(id, doubleSecretMessage.getSecret()); - parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getSecretT()); + parties[i - 1].share = extractShare(id, doubleSecretMessage.getShare()); + parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getShareT()); parties[i - 1].notify(); } } @@ -209,7 +208,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() .setI(doubleSecretMessage.getI()) .setJ(doubleSecretMessage.getJ()) - .setSecret(doubleSecretMessage.getSecret()) + .setShare(doubleSecretMessage.getShare()) .build(); return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); }else{ @@ -230,8 +229,8 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. if(isValidAnswerMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); int j = doubleSecretMessage.getJ(); - Polynomial.Point secret = extractShare(j, doubleSecretMessage.getSecret()); - Polynomial.Point secretT = extractShare(j, doubleSecretMessage.getSecretT()); + 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)) { @@ -310,8 +309,8 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. if (isValidComplaintMessage(sender,isBroadcast,ysComplaintMessage)) { int i = ysComplaintMessage.getI(); int j = ysComplaintMessage.getJ(); - Polynomial.Point secret = extractShare(i,ysComplaintMessage.getSecret()); - Polynomial.Point secretT = extractShare(i,ysComplaintMessage.getSecretT()); + 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]) { diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java index 19c279e..8f971fc 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java @@ -1,15 +1,14 @@ package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; -import Communication.MailHandler; -import Communication.MessageHandler; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; +import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. */ -public class MailHandler extends Communication.MailHandler { +public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler { public MailHandler(MessageHandler messageHandler) { super(messageHandler); diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java index b45d5b5..c30ca97 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java @@ -11,21 +11,20 @@ import java.util.Arrays; * contains all relevant information on specific party during * the run of Joint Feldamn protocol */ -// TODO: comments for every field. public class Party { public final int id; public Polynomial.Point share; public ArrayList commitments; public boolean doneFlag; - public DistributedKeyGeneration.ComplaintState[] complaints; + public Protocol.ComplaintState[] complaints; public boolean aborted; public Party(int id, int n, int t) { this.id = id; this.share = null; this.doneFlag = false; - this.complaints = new DistributedKeyGeneration.ComplaintState[n]; - Arrays.fill(this.complaints, DistributedKeyGeneration.ComplaintState.OK); + this.complaints = new Protocol.ComplaintState[n]; + Arrays.fill(this.complaints, Protocol.ComplaintState.OK); this.commitments = new ArrayList(t + 1); for (int i = 0; i <= t ; i++){ commitments.add(null); diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java index ba0a77b..79a3f9c 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java @@ -146,7 +146,7 @@ public class Protocol extends VerifiableSecretSharing { DKGMessages.ShareMessage.newBuilder() .setI(id) .setJ(j) - .setSecret(secret) + .setShare(secret) .build()); } @@ -221,7 +221,7 @@ public class Protocol extends VerifiableSecretSharing { channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER, DKGMessages.ShareMessage.newBuilder() .setI(id) .setJ(j) - .setSecret(ByteString.copyFrom(getShare(j).y.toByteArray())) + .setShare(ByteString.copyFrom(getShare(j).y.toByteArray())) .build()); } diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java index f225d59..8475aef 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java @@ -1,7 +1,6 @@ package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; import meerkat.crypto.utilitis.Channel; -import Communication.MailHandler; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import com.google.protobuf.ByteString; import com.google.protobuf.Message; @@ -11,7 +10,6 @@ import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; import java.util.ArrayList; import java.util.Set; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGeneration.ComplaintState; /** * Created by Tzlil on 3/14/2016. @@ -20,14 +18,14 @@ import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol */ public class User implements Runnable{ - protected final DistributedKeyGeneration dkg; + protected final Protocol dkg; protected final T g; protected final Group group; protected final int n; protected final int t; protected final int id; - protected MailHandler mailHandler; + protected meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler mailHandler; protected final Channel channel; protected final Party[] parties; @@ -36,7 +34,7 @@ public class User implements Runnable{ protected ArrayList commitments; // public verification values protected T y; // final public value - public User(DistributedKeyGeneration dkg, Channel channel) { + public User(Protocol dkg, Channel channel) { this.dkg = dkg; this.g = dkg.getGenerator(); @@ -61,7 +59,7 @@ public class User implements Runnable{ * create MailHandler and register it as ReceiverCallback */ protected void registerReceiverCallback(){ - this.mailHandler = new DistributedKeyGenerationMailHandler(new MessageHandler()); + this.mailHandler = new MailHandler(new MessageHandler()); channel.registerReceiverCallback(mailHandler); } @@ -148,7 +146,7 @@ public class User implements Runnable{ for (int i = 0; i < n; i++){ for (int j = 0; j < n; j++){ synchronized (parties[i]) { - while (parties[i].complaints[j].equals(ComplaintState.Waiting) && !parties[i].aborted) { + while (parties[i].complaints[j].equals(Protocol.ComplaintState.Waiting) && !parties[i].aborted) { try { parties[i].wait(); } catch (InterruptedException e) { @@ -263,7 +261,7 @@ public class User implements Runnable{ } - public class MessageHandler implements Communication.MessageHandler{ + public class MessageHandler implements meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler{ public MessageHandler(){ @@ -320,7 +318,7 @@ public class User implements Runnable{ DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { int i = secretMessage.getI(); - Polynomial.Point secret = extractShare(id,secretMessage.getSecret()); + Polynomial.Point secret = extractShare(id,secretMessage.getShare()); synchronized (parties[i -1]) { parties[i - 1].share = secret; parties[i - 1].notify(); @@ -358,7 +356,7 @@ public class User implements Runnable{ protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKGMessages.IDMessage complaintMessage){ int i = sender; int j = complaintMessage.getId(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( ComplaintState.OK); + return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK); } /** @@ -371,7 +369,7 @@ public class User implements Runnable{ int i = sender; int j = complaintMessage.getId(); synchronized (parties[j - 1]) { - parties[j - 1].complaints[i - 1] = ComplaintState.Waiting; + parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; parties[j - 1].notify(); } } @@ -390,7 +388,7 @@ public class User implements Runnable{ if(sender != i || !isBroadcast) return false; else - return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(ComplaintState.Waiting); + return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(Protocol.ComplaintState.Waiting); } /** @@ -404,12 +402,12 @@ public class User implements Runnable{ if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { int i = secretMessage.getI(); int j = secretMessage.getJ(); - Polynomial.Point secret = extractShare(j,secretMessage.getSecret()); + Polynomial.Point secret = extractShare(j,secretMessage.getShare()); synchronized (parties[i - 1]) { if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) { - parties[i - 1].complaints[j - 1] = ComplaintState.NonDisqualified; + parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.NonDisqualified; } else { - parties[i - 1].complaints[j - 1] = ComplaintState.Disqualified; + parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.Disqualified; } if (j == id) { parties[i - 1].share = secret; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java index a15f0e2..6f3638b 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java @@ -1,8 +1,7 @@ package meerkat.crypto.concrete.secret_shring.feldman_verifiable; -import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.Polynomial; -import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.SecretSharing; - +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; import org.factcenter.qilin.primitives.Group; import java.util.ArrayList; diff --git a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java index 4ca7b6a..4521fcd 100644 --- a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java +++ b/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java @@ -1,8 +1,8 @@ package Utils; -import Arithmetics.Arithmetic; -import Arithmetics.Fp; -import ShamirSecretSharing.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.utilitis.Arithmetic; +import meerkat.crypto.utilitis.concrete.Fp; import java.math.BigInteger; import java.util.Random; @@ -12,7 +12,7 @@ import java.util.Random; */ public class GenerateRandomPolynomial { - public static Polynomial generateRandomPolynomial(int degree, int bits, Random random,Arithmetic arithmetic) { + public static Polynomial generateRandomPolynomial(int degree, int bits, Random random, Arithmetic arithmetic) { BigInteger[] coefficients = new BigInteger[degree + 1]; for (int i = 0 ; i <= degree; i++ ){ diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java index e4adfc6..34bd672 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java @@ -1,7 +1,7 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +import meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol.*; import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DistributedKeyGeneration; import java.math.BigInteger; import java.util.Random; @@ -10,11 +10,11 @@ import java.util.Set; /** * Created by Tzlil on 3/29/2016. */ -public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUser { +public class SDKGMaliciousUserImpl extends User { - private final DistributedKeyGeneration maliciousSDKG; + private final Protocol maliciousSDKG; private final Set falls; - public SDKGMaliciousUserImpl(SecureDistributedKeyGeneration sdkg, SecureDistributedKeyGeneration maliciousSDKG + public SDKGMaliciousUserImpl(Protocol sdkg, Protocol maliciousSDKG , Channel channel, Set falls) { super(sdkg, channel); this.falls = falls; @@ -22,10 +22,10 @@ public class SDKGMaliciousUserImpl extends SecureDistributedKeyGenerationUser { maliciousSDKG.setParties(parties); } - public static SecureDistributedKeyGeneration generateMaliciousSDKG(SecureDistributedKeyGeneration sdkg,Channel channel,Random random){ + public static Protocol generateMaliciousSDKG(Protocol sdkg,Channel channel,Random random){ BigInteger q = sdkg.getQ(); BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - SecureDistributedKeyGeneration malicious = new SecureDistributedKeyGeneration(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() + Protocol malicious = new Protocol(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ() ,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId(),sdkg.getEncoder()); malicious.setChannel(channel); return malicious; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java index 6e44252..5fc7e04 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java @@ -1,9 +1,9 @@ package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +import Utils.ChannelImpl; import meerkat.crypto.utilitis.Arithmetic; import meerkat.crypto.utilitis.concrete.Fp; import meerkat.crypto.utilitis.Channel; -import Communication.ChannelImpl; import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; @@ -95,14 +95,14 @@ public class SDKGTest { Set QUAL; Set aborted; Set malicious; - SecureDistributedKeyGenerationUser[] sdkgs; + User[] sdkgs; Thread[] threads; BigInteger g; BigInteger h; BigInteger secret; public Testable(Random random) { - this.sdkgs = new SecureDistributedKeyGenerationUser[n]; + this.sdkgs = new User[n]; this.valids = new HashSet(); this.QUAL = new HashSet(); this.aborted = new HashSet(); @@ -117,14 +117,14 @@ public class SDKGTest { int id; BigInteger s; Channel channel; - SecureDistributedKeyGeneration sdkg; + Protocol sdkg; this.secret = BigInteger.ZERO; ByteEncoder encoder = new BigIntegerByteEncoder(); while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); s = randomIntModQ(random); channel = new ChannelImpl(id,n); - sdkg = new SecureDistributedKeyGeneration(t, n, s, random, q, g , h, group, id,encoder); + sdkg = new Protocol(t, n, s, random, q, g , h, group, id,encoder); sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg,random); threads[id - 1] = new Thread(sdkgs[id - 1]); if(QUAL.contains(id)){ @@ -134,18 +134,18 @@ public class SDKGTest { } - public SecureDistributedKeyGenerationUser randomSDKGUser(int id, Channel channel, SecureDistributedKeyGeneration sdkg, Random random){ + public User randomSDKGUser(int id, Channel channel, Protocol sdkg, Random random){ if (QUAL.size() <= t) { valids.add(id); QUAL.add(id); - return new SecureDistributedKeyGenerationUser(sdkg,channel); + return new User(sdkg,channel); }else{ int type = random.nextInt(3); switch (type){ case 0:// regular valids.add(id); QUAL.add(id); - return new SecureDistributedKeyGenerationUser(sdkg,channel); + return new User(sdkg,channel); case 1:// abort int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 aborted.add(id); @@ -156,7 +156,7 @@ public class SDKGTest { case 2:// malicious malicious.add(id); Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - SecureDistributedKeyGeneration maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); + Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); default: return null; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java index 2690048..0a7bb12 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java @@ -6,11 +6,11 @@ import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 3/14/2016. */ -public class SDKGUserImplAbort extends SecureDistributedKeyGenerationUser { +public class SDKGUserImplAbort extends User { final int abortStage; int stage; - public SDKGUserImplAbort(SecureDistributedKeyGeneration sdkg, Channel channel, int abortStage) { + public SDKGUserImplAbort(Protocol sdkg, Channel channel, int abortStage) { super(sdkg, channel); this.abortStage = abortStage;// 1 - 4 this.stage = 1; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java index 2c7bea2..f20076d 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java @@ -8,11 +8,11 @@ import java.util.*; /** * Created by Tzlil on 3/21/2016. */ -public class DKGMaliciousUser extends DistributedKeyGenerationUser { +public class DKGMaliciousUser extends User { - private final DistributedKeyGeneration maliciousDkg; + private final Protocol maliciousDkg; private final Set falls; - public DKGMaliciousUser(DistributedKeyGeneration dkg, DistributedKeyGeneration maliciousDKG, Channel channel, Set falls) { + public DKGMaliciousUser(Protocol dkg, Protocol maliciousDKG, Channel channel, Set falls) { super(dkg, channel); this.falls = falls; this.maliciousDkg = maliciousDKG; @@ -32,10 +32,10 @@ public class DKGMaliciousUser extends DistributedKeyGenerationUser { return falls; } - public static DistributedKeyGeneration generateMaliciousDKG(DistributedKeyGeneration dkg,Channel channel,Random random){ + public static Protocol generateMaliciousDKG(Protocol dkg,Channel channel,Random random){ BigInteger q = dkg.getQ(); BigInteger zi = new BigInteger(q.bitLength(), random).mod(q); - DistributedKeyGeneration malicious = new DistributedKeyGeneration(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() + Protocol malicious = new Protocol(dkg.getT(),dkg.getN(),zi,random,dkg.getQ() ,dkg.getGenerator(),dkg.getGroup(),dkg.getId(),dkg.getEncoder()); malicious.setChannel(channel); return malicious; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java index f4b2780..19693f5 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java @@ -1,14 +1,15 @@ package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +import Utils.ChannelImpl; import meerkat.crypto.utilitis.Arithmetic; import meerkat.crypto.utilitis.concrete.Fp; import meerkat.crypto.utilitis.Channel; -import Communication.ChannelImpl; import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; import Utils.BigIntegerByteEncoder; import Utils.GenerateRandomPrime; +import meerkat.protobuf.Crypto; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; @@ -95,13 +96,13 @@ public class DKGTest { Set QUAL; Set aborted; Set malicious; - DistributedKeyGenerationUser[] dkgs; + User[] dkgs; Thread[] threads; BigInteger g; BigInteger secret; public Testable(Random random) { - this.dkgs = new DistributedKeyGenerationUser[n]; + this.dkgs = new User[n]; this.valids = new HashSet(); this.QUAL = new HashSet(); this.aborted = new HashSet(); @@ -114,7 +115,7 @@ public class DKGTest { } int id; BigInteger s; - DistributedKeyGeneration dkg; + Protocol dkg; this.secret = BigInteger.ZERO; Channel channel; ByteEncoder byteEncoder = new BigIntegerByteEncoder(); @@ -122,7 +123,7 @@ public class DKGTest { id = ids.remove(random.nextInt(ids.size())); channel = new ChannelImpl(id,n); s = randomIntModQ(random); - dkg = new DistributedKeyGeneration(t, n, s, random, q, g, group, id,byteEncoder); + dkg = new meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol(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)){ @@ -132,18 +133,18 @@ public class DKGTest { } - public DistributedKeyGenerationUser randomDKGUser(int id, Channel channel, DistributedKeyGeneration dkg, Random random){ + public User randomDKGUser(int id, Channel channel, Protocol dkg, Random random){ if (QUAL.size() <= t) { valids.add(id); QUAL.add(id); - return new DistributedKeyGenerationUser(dkg,channel); + return new User(dkg,channel); }else{ int type = random.nextInt(3); switch (type){ case 0:// regular valids.add(id); QUAL.add(id); - return new DistributedKeyGenerationUser(dkg,channel); + return new User(dkg,channel); case 1:// abort int abortStage = random.nextInt(2) + 1; // 1 or 2 aborted.add(id); @@ -154,7 +155,7 @@ public class DKGTest { case 2:// malicious malicious.add(id); Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - DistributedKeyGeneration maliciousDKG = DKGMaliciousUser.generateMaliciousDKG(dkg,channel,random); + Protocol maliciousDKG = DKGMaliciousUser.generateMaliciousDKG(dkg,channel,random); return new DKGMaliciousUser(dkg,maliciousDKG,channel,falls); default: return null; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java index 88a0847..2e42299 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java @@ -6,11 +6,11 @@ import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 3/14/2016. */ -public class DKGUserImplAbort extends DistributedKeyGenerationUser { +public class DKGUserImplAbort extends User { final int abortStage; int stage; - public DKGUserImplAbort(DistributedKeyGeneration dkg, Channel channel, int abortStage) { + public DKGUserImplAbort(Protocol dkg, Channel channel, int abortStage) { super(dkg, channel); this.abortStage = abortStage;// 1 - 2 this.stage = 1; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java index f7d3a39..f106584 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java @@ -1,6 +1,6 @@ package meerkat.crypto.concrete.secret_shring.feldman_verifiable; -import meerkat.crypto.concrete.secret_shring.ShamirSecretSharing.Polynomial; +import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java index 2c78b03..326b0bf 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java @@ -1,6 +1,6 @@ package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; -import Arithmetics.Z; import Utils.GenerateRandomPolynomial; +import Utils.Z; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java index 30e2082..36c42ad 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java @@ -1,7 +1,7 @@ package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; -import Arithmetics.Z; import Utils.GenerateRandomPolynomial; +import Utils.Z; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java index 8af27ab..1a83f50 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java @@ -1,7 +1,7 @@ package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; -import Arithmetics.Z; import Utils.GenerateRandomPolynomial; +import Utils.Z; import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto index 81072e9..046f586 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/meerkat-common/src/main/proto/meerkat/DKGMessages.proto @@ -6,7 +6,7 @@ option java_package = "meerkat.protobuf"; message Mail{ enum Type { - SECRET = 0; + SHARE = 0; COMMITMENT = 1; COMPLAINT = 2; DONE = 3; @@ -23,17 +23,17 @@ message Mail{ bytes message = 5; } -message SecretMessage { +message ShareMessage { int32 i = 1; int32 j = 2; - bytes secret = 3; + bytes share = 3; } -message DoubleSecretMessage{ +message DoubleShareMessage{ int32 i = 1; int32 j = 2; - bytes secret = 3; - bytes secretT = 4; + bytes share = 3; + bytes shareT = 4; } message CommitmentMessage{ From d0951f8644a46247bbc49b1935ecd9078a0776bc Mon Sep 17 00:00:00 2001 From: "tzlil.gon" Date: Fri, 8 Apr 2016 21:48:08 +0300 Subject: [PATCH 039/106] stop --- .../bulletinboard/BulletinClientWorker.java | 4 +- .../SimpleBulletinBoardClient.java | 4 +- .../ThreadedBulletinBoardClient.java | 4 +- .../sqlserver/BulletinBoardSQLServer.java | 4 +- .../GenericBulletinBoardServerTest.java | 2 +- .../java/meerkat/crypto/KeyGeneration.java | 11 - .../java/meerkat/crypto/SecretSharing.java | 7 - .../meerkat/crypto/utilitis/Arithmetic.java | 18 - .../communication}/MailHandler.java | 31 +- .../communication}/MessageHandler.java | 28 +- .../gjkr_secure_protocol/MailHandler.java | 23 +- .../gjkr_secure_protocol/Party.java | 6 +- .../gjkr_secure_protocol/Protocol.java | 8 +- .../gjkr_secure_protocol/User.java | 71 +- .../joint_feldman_protocol/MailHandler.java | 11 +- .../joint_feldman_protocol/Party.java | 10 +- .../joint_feldman_protocol/Protocol.java | 14 +- .../joint_feldman_protocol/User.java | 146 +++- .../VerifiableSecretSharing.java | 22 +- .../shamir/LagrangePolynomial.java | 4 +- .../secret_shring/shamir/Polynomial.java | 6 +- .../secret_shring/shamir/SecretSharing.java | 18 +- .../utilitis/Arithmetic.java | 38 ++ .../utilitis/Channel.java | 16 +- .../utilitis/concrete/Fp.java | 9 +- .../SDKGMaliciousUserImpl.java | 5 +- .../gjkr_secure_protocol/SDKGTest.java | 53 +- .../SDKGUserImplAbort.java | 4 +- .../DKGMaliciousUser.java | 4 +- .../joint_feldman_protocol/DKGTest.java | 53 +- .../DKGUserImplAbort.java | 4 +- .../VerifiableSecretSharingTest.java | 4 +- .../shamir/PolynomialTests/AddTest.java | 8 +- .../PolynomialTests/InterpolationTest.java | 12 +- .../PolynomialTests/MulByConstTest.java | 8 +- .../shamir/PolynomialTests/MulTest.java | 8 +- .../shamir/SecretSharingTest.java | 6 +- .../utilitis}/BigIntegerByteEncoder.java | 2 +- .../utilitis}/ChannelImpl.java | 11 +- .../utilitis}/GenerateRandomPolynomial.java | 61 +- .../utilitis}/GenerateRandomPrime.java | 62 +- .../utilitis}/Z.java | 4 +- .../Digest.java | 76 +-- .../DigitalSignature.java | 192 +++--- .../Encryption.java | 80 +-- .../concrete/ECDSADeterministicSignature.java | 268 ++++---- .../concrete/ECDSASignature.java | 644 +++++++++--------- .../concrete/ECElGamalEncryption.java | 270 ++++---- .../concrete/GlobalCryptoSetup.java | 86 +-- .../concrete/SHA256Digest.java | 192 +++--- .../mixnet/Mix2ZeroKnowledgeProver.java | 36 +- .../mixnet/Mix2ZeroKnowledgeVerifier.java | 46 +- .../mixnet/Mixer.java | 22 +- .../mixnet/Trustee.java | 14 +- .../mixnet/Verifier.java | 14 +- .../ECDSADeterministicSignatureTest.java | 99 ++- .../concrete/ECDSASignatureTest.java | 439 ++++++------ .../concrete/ECElGamalEncryptionTest.java | 244 +++---- .../concrete/ECElGamalUtils.java | 178 ++--- 59 files changed, 1974 insertions(+), 1750 deletions(-) delete mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java delete mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java delete mode 100644 destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java rename destributed-key-generation/src/main/java/meerkat/{crypto/concrete/distributed_key_generation/Communication => destributed_key_generation/concrete/distributed_key_generation/communication}/MailHandler.java (69%) rename destributed-key-generation/src/main/java/meerkat/{crypto/concrete/distributed_key_generation/Communication => destributed_key_generation/concrete/distributed_key_generation/communication}/MessageHandler.java (51%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java (74%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java (68%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java (92%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/User.java (84%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java (75%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/Party.java (70%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java (94%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/User.java (80%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java (81%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/LagrangePolynomial.java (94%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/Polynomial.java (95%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/SecretSharing.java (88%) create mode 100644 destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/utilitis/Channel.java (60%) rename destributed-key-generation/src/main/java/meerkat/{crypto => destributed_key_generation}/utilitis/concrete/Fp.java (74%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java (89%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java (80%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java (89%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java (92%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java (78%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java (88%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java (93%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/PolynomialTests/AddTest.java (78%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java (80%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java (77%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/PolynomialTests/MulTest.java (78%) rename destributed-key-generation/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/secret_shring/shamir/SecretSharingTest.java (90%) rename destributed-key-generation/src/test/java/{Utils => meerkat/destributed_key_generation/utilitis}/BigIntegerByteEncoder.java (91%) rename destributed-key-generation/src/test/java/{Utils => meerkat/destributed_key_generation/utilitis}/ChannelImpl.java (96%) rename destributed-key-generation/src/test/java/{Utils => meerkat/destributed_key_generation/utilitis}/GenerateRandomPolynomial.java (82%) rename destributed-key-generation/src/test/java/{Utils => meerkat/destributed_key_generation/utilitis}/GenerateRandomPrime.java (92%) rename destributed-key-generation/src/test/java/{Utils => meerkat/destributed_key_generation/utilitis}/Z.java (90%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/Digest.java (92%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/DigitalSignature.java (96%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/Encryption.java (94%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/ECDSADeterministicSignature.java (96%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/ECDSASignature.java (96%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/ECElGamalEncryption.java (96%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/GlobalCryptoSetup.java (92%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/concrete/SHA256Digest.java (93%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/mixnet/Mix2ZeroKnowledgeProver.java (93%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/mixnet/Mix2ZeroKnowledgeVerifier.java (91%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/mixnet/Mixer.java (79%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/mixnet/Trustee.java (56%) rename meerkat-common/src/main/java/meerkat/{crypto => destributed_key_generation}/mixnet/Verifier.java (56%) rename meerkat-common/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/ECDSADeterministicSignatureTest.java (91%) rename meerkat-common/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/ECDSASignatureTest.java (96%) rename meerkat-common/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/ECElGamalEncryptionTest.java (96%) rename meerkat-common/src/test/java/meerkat/{crypto => destributed_key_generation}/concrete/ECElGamalUtils.java (96%) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index 1d0d741..b519eb4 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -2,8 +2,8 @@ package meerkat.bulletinboard; import com.google.protobuf.Message; import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; +import meerkat.destributed_key_generation.Digest; +import meerkat.destributed_key_generation.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; import meerkat.rest.ProtobufMessageBodyReader; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 9d3f24a..b12649e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -2,8 +2,8 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; +import meerkat.destributed_key_generation.Digest; +import meerkat.destributed_key_generation.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting; import meerkat.protobuf.Voting.BulletinBoardClientParams; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 81513f8..d3957cf 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -6,8 +6,8 @@ import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; import meerkat.comm.CommunicationException; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; +import meerkat.destributed_key_generation.Digest; +import meerkat.destributed_key_generation.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 8402e55..2c0a8d7 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -13,8 +13,8 @@ import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; +import meerkat.destributed_key_generation.Digest; +import meerkat.destributed_key_generation.concrete.SHA256Digest; import javax.sql.DataSource; diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 1c5e3c5..fa4c60b 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -18,7 +18,7 @@ import java.util.Random; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; -import meerkat.crypto.concrete.ECDSASignature; +import meerkat.destributed_key_generation.concrete.ECDSASignature; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.MessageFilter; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java b/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java deleted file mode 100644 index a6db4f9..0000000 --- a/destributed-key-generation/src/main/java/meerkat/crypto/KeyGeneration.java +++ /dev/null @@ -1,11 +0,0 @@ -package meerkat.crypto; - -import java.util.Random; - -/** - * Created by Tzlil on 4/8/2016. - */ -public interface KeyGeneration { - - T generateKey(Random random); -} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java b/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java deleted file mode 100644 index e7619b6..0000000 --- a/destributed-key-generation/src/main/java/meerkat/crypto/SecretSharing.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.crypto; - -/** - * Created by Tzlil on 4/8/2016. - */ -public class SecretSharing { -} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java b/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java deleted file mode 100644 index 618210a..0000000 --- a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Arithmetic.java +++ /dev/null @@ -1,18 +0,0 @@ -package meerkat.crypto.utilitis; - -/** - * Created by Tzlil on 3/17/2016. - */ -public interface Arithmetic { - /** - * - * @param a - * @param b - * @return - */ - T add(T a, T b); - T sub(T a, T b); - T mul(T a, T b); - T div(T a, T b); - -} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java similarity index 69% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java index c646a5a..cc3b08b 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java @@ -1,36 +1,59 @@ -package meerkat.crypto.concrete.distributed_key_generation.communication; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication; import com.google.protobuf.Message; -import meerkat.crypto.utilitis.Channel; +import meerkat.destributed_key_generation.utilitis.Channel; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/14/2016. + * + * an implementation of ReceiverCallback */ public abstract class MailHandler implements Channel.ReceiverCallback{ + /** + * fixed value for broadcasting + */ public static final int BROADCAST = 0; + + /** + * message handler + */ private MessageHandler messageHandler; + /** + * constructor + * @param messageHandler + */ public MailHandler(MessageHandler messageHandler){ this.messageHandler = messageHandler; } + /** + * extract message from mail + * @param mail + * @return + */ public abstract Message extractMessage(DKGMessages.Mail mail); + /** + * is this mail was received by broadcast channel + * @param mail + * @return mail user destination == BROADCAST + */ public boolean isBroadcast(DKGMessages.Mail mail){ return mail.getDestination() == BROADCAST; } + @Override public void receiveMail(DKGMessages.Mail mail){ - Message message = extractMessage(mail); if (message == null) return; switch (mail.getType()) { case SHARE: - messageHandler.handleSecretMessage(mail.getSender(), isBroadcast(mail),message); + messageHandler.handleShareMessage(mail.getSender(), isBroadcast(mail),message); break; case COMMITMENT: messageHandler.handleCommitmentMessage(mail.getSender(), isBroadcast(mail),message); diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java similarity index 51% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java index a58cbcc..0fa7a46 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/Communication/MessageHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java @@ -1,15 +1,39 @@ -package meerkat.crypto.concrete.distributed_key_generation.communication; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication; import com.google.protobuf.Message; /** * Created by Tzlil on 2/14/2016. + * an interface for handling received messages */ public interface MessageHandler { - void handleSecretMessage(int sender, boolean isBroadcast, Message message); + /** + * handle share message + */ + void handleShareMessage(int sender, boolean isBroadcast, Message message); + + /** + * handle commitment message + */ void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); + + /** + * handle complaint message + */ void handleComplaintMessage(int sender, boolean isBroadcast, Message message); + + /** + * handle done message + */ void handleDoneMessage(int sender, boolean isBroadcast, Message message); + + /** + * handle answer message + */ void handleAnswerMessage(int sender, boolean isBroadcast, Message message); + + /** + * handle abort message + */ void handleAbortMessage(int sender, boolean isBroadcast, Message message); } diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java similarity index 74% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java index c35fe6c..5f3ee3b 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java @@ -1,17 +1,26 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler; +import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. + * an extension of MailHandler matching gjkr protocl */ -public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler { +public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler { + /** + * flag that indicants whether the + * current run achieved stage 4 of the protocol or not + */ private boolean isStage4; + /** + * constructor + * @param messageHandler + */ public MailHandler(MessageHandler messageHandler) { super(messageHandler); this.isStage4 = false; @@ -52,10 +61,10 @@ public class MailHandler extends meerkat.crypto.concrete.distributed_key_generat } } - public boolean isStage4() { - return isStage4; - } - + /** + * setter + * @param stage4 + */ public void setStage4(boolean stage4) { isStage4 = stage4; } diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java similarity index 68% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java index c0ee63a..d950beb 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import java.util.ArrayList; import java.util.HashSet; @@ -13,7 +13,7 @@ import java.util.Set; * contains all relevant information on specific party during * the run of the safe protocol */ -public class Party extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Party { +public class Party extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Party { public Polynomial.Point shareT; public boolean ysDoneFlag; public ArrayList verifiableValues; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java similarity index 92% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java index 13ff0e6..a0512d6 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; @@ -17,7 +17,7 @@ import java.util.Set; * TODO: comments * TODO: put Channel (ChannelImpl) in constructor */ -public class Protocol extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol { +public class Protocol extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol { private VerifiableSecretSharing maskingShares; private final T h; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java similarity index 84% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java index f976ff9..86ed127 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/User.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java @@ -1,10 +1,10 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.concrete.Fp; -import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; +import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; @@ -13,25 +13,48 @@ import java.util.ArrayList; /** * Created by Tzlil on 3/16/2016. + * + * implementation of gjkr protocol user. + * + * this protocol extends joint feldman protocol by splitting the protocol to commitment stage (stages 1,2,3) + * and reviling stage (stage 4). + * + * 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 extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User { +public class User extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User { + /** + * All parties participating in key generation. + * parties[id-1] has my info. + */ protected Party[] parties; - protected final Protocol sdkg; - private Arithmetic arithmetic; - private boolean isStage4; + /** + * gjkr secure protocol object + */ + protected final Protocol sdkg; + + /** + * message handler + */ + private MessageHandler messageHandler; + + /** + * constructor + * @param sdkg gjkr protocol object + * @param channel channel object + */ public User(Protocol sdkg, Channel channel) { super(sdkg, channel); this.sdkg = sdkg; this.parties = sdkg.getParties(); - this.arithmetic = new Fp(sdkg.getQ()); - this.isStage4 = false; } @Override protected void registerReceiverCallback(){ - this.mailHandler = new MailHandler(new MessageHandler()); + this.messageHandler = new MessageHandler(); + this.mailHandler = new MailHandler(messageHandler); this.channel.registerReceiverCallback(mailHandler); } /** @@ -84,7 +107,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. try { parties[i - 1].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } @@ -102,7 +125,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. try { parties[i - 1].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } @@ -122,13 +145,13 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. try { parties[i - 1].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } } } - + Arithmetic arithmetic = new Fp(sdkg.getQ()); // restore necessary information for (int i = 0; i < n ; i++) { if(parties[i].recoverSharesSet.isEmpty()){ @@ -152,10 +175,10 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. } /** - * notifies mail handler that stage 4 was started + * notifies mail handler and message handler that stage 4 was started */ protected void setStage4(){ - this.isStage4 = true; + this.messageHandler.isStage4 = true; ((MailHandler)this.mailHandler).setStage4(true); } @@ -163,11 +186,13 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. protected void stage4() { setStage4(); resolveQualifyingPublicKey(); + if (stop) return; super.stage4(); } - private class MessageHandler extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler { + private class MessageHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler { + boolean isStage4; /** * as in super, with extension to double secret message */ @@ -184,7 +209,7 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. * as in super, with extension to double secret message */ @Override - public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + public void handleShareMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message; if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) { int i = doubleSecretMessage.getI(); @@ -234,10 +259,10 @@ public class User extends meerkat.crypto.concrete.distributed_key_generation. synchronized (parties[i - 1]) { if (!isStage4) { if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified; + parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified; } else { - parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.Disqualified; + parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.Disqualified; } if (j == id) { parties[i - 1].share = secret; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java similarity index 75% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java index 8f971fc..a2d82b2 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java @@ -1,15 +1,20 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler; +import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. + * an extension of MailHandler matching joint feldman protocol */ -public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler { +public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler { + /** + * constructor + * @param messageHandler + */ public MailHandler(MessageHandler messageHandler) { super(messageHandler); } diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java similarity index 70% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java index c30ca97..90ee829 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Party.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import java.util.ArrayList; import java.util.Arrays; @@ -19,6 +19,12 @@ public class Party { 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; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java similarity index 94% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java index 79a3f9c..e3cddbd 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java @@ -1,8 +1,8 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; @@ -57,7 +57,6 @@ public class Protocol extends VerifiableSecretSharing { */ protected Channel channel; - /** * Encode/Decode group elements */ @@ -76,9 +75,10 @@ public class Protocol extends VerifiableSecretSharing { * @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 group, int id, ByteEncoder byteEncoder) { + , Group group, int id, ByteEncoder encoder) { super(t, n, zi, random, q, g,group); this.id = id; this.parties = new Party[n]; @@ -86,7 +86,7 @@ public class Protocol extends VerifiableSecretSharing { this.parties[i - 1] = new Party(i,n,t); } this.parties[id - 1].share = getShare(id); - this.encoder = byteEncoder; + this.encoder = encoder; } /** diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java similarity index 80% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java index 8475aef..84f5bb8 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/User.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; @@ -13,27 +13,91 @@ import java.util.Set; /** * Created by Tzlil on 3/14/2016. - * TODO: Comments - * TODO: Replace polling with monitors/wait/notify (remember synchronization) + * + * 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 implements Runnable{ + /** + * joint feldman protocol object + */ protected final Protocol 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 group; - protected final int n; - protected final int t; + + /** + * user id + */ protected final int id; - protected meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler mailHandler; - protected final Channel channel; + /** + * threshold + */ + protected final int t; + + /** + * number of shares + */ + protected final int n; + + /** + * mail handler registered to channel as ReceiverCallback + */ + protected meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler mailHandler; + + /** + * channel object + */ + protected final Channel channel; // + + /** + * All parties participating in key generation. + * parties[id-1] has my info. + */ protected final Party[] parties; - protected Set QUAL; // set of all non-disqualified parties - protected Polynomial.Point share; // final share of the secrete - protected ArrayList commitments; // public verification values - protected T y; // final public value + /** + * set of all non-disqualified parties + */ + protected Set QUAL; + + /** + * my own share of the generated random key. + */ + protected Polynomial.Point share; + + /** + * public verification values + */ + protected ArrayList commitments; + + /** + * public value, + * y = g ^ key + */ + protected T y; + + /** + * constructor + * @param dkg joint feldman protocol object + * @param channel channel object + */ public User(Protocol dkg, Channel channel) { this.dkg = dkg; @@ -74,20 +138,23 @@ public class User implements Runnable{ } + /** + * wait for all shares and commitments will arrive from other parties + */ protected void waitUntilStageOneCompleted(){ - // all parties send their share or aborted + // wait for parties' share for (int i = 0 ; i < n ; i++){ synchronized (parties[i]) { while (parties[i].share == null && !parties[i].aborted) { try { parties[i].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } } - // all parties broadcast their commitments or aborted + // wait for parties' commitments for (int i = 0 ; i < n ; i++){ for (int k = 0 ; k <= t ; k++) { synchronized (parties[i]) { @@ -95,7 +162,7 @@ public class User implements Runnable{ try { parties[i].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } @@ -117,15 +184,17 @@ public class User implements Runnable{ } + /** + * wait until all other parties done complaining by receiving done message + */ protected void waitUntilStageTwoCompleted(){ - // all parties done or aborted for (int i = 0 ; i < n ; i++){ synchronized (parties[i]) { while (!parties[i].doneFlag && !parties[i].aborted) { try { parties[i].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } @@ -150,7 +219,7 @@ public class User implements Runnable{ try { parties[i].wait(); } catch (InterruptedException e) { - //do nothing + if (stop) return; } } } @@ -173,18 +242,38 @@ public class User implements Runnable{ @Override public void run() { + this.runThread = Thread.currentThread(); stage1(); waitUntilStageOneCompleted(); + if (stop) return; stage2(); waitUntilStageTwoCompleted(); + if (stop) return; stage3(); + if (stop) return; stage4(); } + /** + * 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 + } } @@ -260,12 +349,19 @@ public class User implements Runnable{ return QUAL; } + /** + * getter + * @return channel + */ + public Channel getChannel() { + return channel; + } - public class MessageHandler implements meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler{ + /** + * an implementation of MessageHandler + */ + public class MessageHandler implements meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler{ - public MessageHandler(){ - - } /** * commitment message is valid if: * 1. it was received in broadcast chanel @@ -314,7 +410,7 @@ public class User implements Runnable{ * saves the secret */ @Override - public void handleSecretMessage(int sender, boolean isBroadcast, Message message) { + public void handleShareMessage(int sender, boolean isBroadcast, Message message) { DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { int i = secretMessage.getI(); diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java similarity index 81% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java index 6f3638b..1544564 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.secret_shring.feldman_verifiable; +package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; import org.factcenter.qilin.primitives.Group; import java.util.ArrayList; @@ -17,12 +17,22 @@ import java.util.Random; * */ public class VerifiableSecretSharing extends SecretSharing { + /** + * cyclic group contains g. + */ protected final Group group; - protected final T g; // public generator of 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 commitmentsArrayList; - - /** * constructor * @param q a large prime. diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java similarity index 94% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java index 20aee54..0da8f48 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/LagrangePolynomial.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.secret_shring.shamir; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir; -import meerkat.crypto.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.Arithmetic; import java.math.BigInteger; diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java similarity index 95% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java index c2d77ff..e0e2361 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/Polynomial.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.secret_shring.shamir; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir; -import meerkat.crypto.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.Arithmetic; import java.math.BigInteger; import java.util.Arrays; @@ -100,7 +100,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new meerkat.crypto.concrete.secret_shring.shamir.Polynomial of degree max(this degree,other degree) s.t for all x + * @return new meerkat.destributed_key_generation.concrete.secret_shring.shamir.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){ diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java similarity index 88% rename from destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java index 87853d5..d5e73aa 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharing.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.secret_shring.shamir; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; import java.math.BigInteger; import java.util.Random; @@ -11,9 +11,21 @@ import java.util.Random; * 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; /** diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java new file mode 100644 index 0000000..2aab0cf --- /dev/null +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java @@ -0,0 +1,38 @@ +package meerkat.destributed_key_generation.utilitis; + +/** + * 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 { + /** + * 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); + +} diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java similarity index 60% rename from destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java index 2be0bf4..294ffaf 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/Channel.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java @@ -1,10 +1,10 @@ -package meerkat.crypto.utilitis; +package meerkat.destributed_key_generation.utilitis; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; /** - * A generic commmunication channel that supports point-to-point and broadcast operation + * A generic communication channel that supports point-to-point and broadcast operation */ public interface Channel { @@ -12,8 +12,20 @@ public interface Channel { public void receiveMail(DKGMessages.Mail mail); } + /** + * sends a private message + * @param destUser destination user's identifier + * @param type message type + * @param msg message + */ public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg); + + /** + * broadcasts a message to all parties (including the sender) + * @param type message type + * @param msg message + */ public void broadcastMessage(DKGMessages.Mail.Type type, Message msg); /** diff --git a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java similarity index 74% rename from destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java rename to destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java index e538293..d7d03bc 100644 --- a/destributed-key-generation/src/main/java/meerkat/crypto/utilitis/concrete/Fp.java +++ b/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java @@ -1,17 +1,22 @@ -package meerkat.crypto.utilitis.concrete; +package meerkat.destributed_key_generation.utilitis.concrete; -import meerkat.crypto.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.Arithmetic; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; /** * Created by Tzlil on 3/17/2016. + * an implementation of Arithmetic over prime fields: integers modulo p */ public class Fp implements Arithmetic { public final BigInteger p; private final Zpstar zp; + /** + * constructor + * @param p prime + */ public Fp(BigInteger p) { this.p = p; this.zp = new Zpstar(p); diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java similarity index 89% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java index 34bd672..7afb60e 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java @@ -1,7 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol.*; -import meerkat.crypto.utilitis.Channel; +import meerkat.destributed_key_generation.utilitis.Channel; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java similarity index 80% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java index 5fc7e04..d296810 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java @@ -1,15 +1,15 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import Utils.ChannelImpl; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.concrete.Fp; -import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; -import Utils.BigIntegerByteEncoder; -import Utils.GenerateRandomPrime; +import meerkat.destributed_key_generation.utilitis.ChannelImpl; +import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; +import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; @@ -27,25 +27,16 @@ import java.util.Set; */ public class SDKGTest { - int tests = 1; + int tests = 10; BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); Group group = new Zpstar(p); Arithmetic arithmetic = new Fp(q); int t = 9; int n = 20; - Testable[] testables; - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; + public void oneTest(Testable testable) throws Exception { for (int i = 0; i < testable.threads.length ; i++){ testable.threads[i].start(); } @@ -83,13 +74,23 @@ public class SDKGTest { assert (calculatedSecret.equals(testable.secret)); } - @Test - public void test() throws Exception { - for (int i = 0; i < tests; i++){ - oneTest(i); + public void stopReceivers(Testable testable){ + ChannelImpl channel; + for (int i = 0 ; i < testable.sdkgs.length ; i++){ + channel = (ChannelImpl)testable.sdkgs[i].getChannel(); + channel.stop(); } } + @Test + public void test() throws Exception { + Testable testable; + for (int i = 0; i < tests; i++) { + testable = new Testable(new Random()); + oneTest(testable); + stopReceivers(testable); + } + } class Testable{ Set valids; Set QUAL; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java similarity index 89% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java index 0a7bb12..e91d87e 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; -import meerkat.crypto.utilitis.Channel; +import meerkat.destributed_key_generation.utilitis.Channel; import meerkat.protobuf.DKGMessages; /** diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java similarity index 92% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java index f20076d..672de21 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import meerkat.crypto.utilitis.Channel; +import meerkat.destributed_key_generation.utilitis.Channel; import java.math.BigInteger; import java.util.*; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java similarity index 78% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java index 19693f5..cac11df 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java @@ -1,15 +1,14 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import Utils.ChannelImpl; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.concrete.Fp; -import meerkat.crypto.utilitis.Channel; -import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing; -import Utils.BigIntegerByteEncoder; -import Utils.GenerateRandomPrime; -import meerkat.protobuf.Crypto; +import meerkat.destributed_key_generation.utilitis.ChannelImpl; +import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; +import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; @@ -27,7 +26,7 @@ import java.util.Set; */ public class DKGTest { - int tests = 1; + int tests = 10; BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); Group group = new Zpstar(p); @@ -35,18 +34,7 @@ public class DKGTest { int t = 9; int n = 20; - Testable[] testables; - - @Before - public void settings(){ - testables = new Testable[tests]; - for (int i = 0; i < tests; i++){ - testables[i] = new Testable(new Random()); - } - } - - public void oneTest(int test) throws Exception { - Testable testable = testables[test]; + public void oneTest(Testable testable) throws Exception { for (int i = 0; i < testable.threads.length ; i++){ testable.threads[i].start(); } @@ -84,10 +72,21 @@ public class DKGTest { assert (calculatedSecret.equals(testable.secret)); } + public void stopReceivers(Testable testable){ + ChannelImpl channel; + for (int i = 0 ; i < testable.dkgs.length ; i++){ + channel = (ChannelImpl)testable.dkgs[i].getChannel(); + channel.stop(); + } + } + @Test public void test() throws Exception { + Testable testable; for (int i = 0; i < tests; i++){ - oneTest(i); + testable = new Testable(new Random()); + oneTest(testable); + stopReceivers(testable); } } @@ -117,13 +116,13 @@ public class DKGTest { BigInteger s; Protocol dkg; this.secret = BigInteger.ZERO; - Channel channel; + ChannelImpl channel; ByteEncoder byteEncoder = new BigIntegerByteEncoder(); while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); channel = new ChannelImpl(id,n); s = randomIntModQ(random); - dkg = new meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol(t, n, s, random, q, g, group, id,byteEncoder); + dkg = new meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol(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)){ diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java similarity index 88% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java index 2e42299..dc0f419 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; -import meerkat.crypto.utilitis.Channel; +import meerkat.destributed_key_generation.utilitis.Channel; import meerkat.protobuf.DKGMessages; /** diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java similarity index 93% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java index f106584..1f2d15e 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java @@ -1,6 +1,6 @@ -package meerkat.crypto.concrete.secret_shring.feldman_verifiable; +package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java similarity index 78% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java index 326b0bf..24c5e9f 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/AddTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; -import Utils.GenerateRandomPolynomial; -import Utils.Z; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; +import meerkat.destributed_key_generation.utilitis.Z; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java similarity index 80% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java index 0183d3f..9462cec 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java @@ -1,10 +1,10 @@ -package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.concrete.Fp; -import Utils.GenerateRandomPolynomial; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import Utils.GenerateRandomPrime; +import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java similarity index 77% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java index 36c42ad..f63fc2b 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java @@ -1,8 +1,8 @@ -package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; -import Utils.GenerateRandomPolynomial; -import Utils.Z; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; +import meerkat.destributed_key_generation.utilitis.Z; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java similarity index 78% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java index 1a83f50..e9caa66 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/PolynomialTests/MulTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java @@ -1,8 +1,8 @@ -package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; -import Utils.GenerateRandomPolynomial; -import Utils.Z; -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; +import meerkat.destributed_key_generation.utilitis.Z; +import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java similarity index 90% rename from destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java index 0396916..cf1b8d3 100644 --- a/destributed-key-generation/src/test/java/meerkat/crypto/concrete/secret_shring/shamir/SecretSharingTest.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java @@ -1,7 +1,7 @@ -package meerkat.crypto.concrete.secret_shring.shamir; +package meerkat.destributed_key_generation.concrete.secret_shring.shamir; -import meerkat.crypto.utilitis.concrete.Fp; -import Utils.GenerateRandomPrime; +import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; import org.factcenter.qilin.primitives.CyclicGroup; import org.factcenter.qilin.primitives.concrete.Zn; import org.junit.Before; diff --git a/destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java similarity index 91% rename from destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java index a0c7107..4548451 100644 --- a/destributed-key-generation/src/test/java/Utils/BigIntegerByteEncoder.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java @@ -1,4 +1,4 @@ -package Utils; +package meerkat.destributed_key_generation.utilitis; import java.math.BigInteger; diff --git a/destributed-key-generation/src/test/java/Utils/ChannelImpl.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java similarity index 96% rename from destributed-key-generation/src/test/java/Utils/ChannelImpl.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java index 31bf748..f6e09f1 100644 --- a/destributed-key-generation/src/test/java/Utils/ChannelImpl.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java @@ -1,7 +1,6 @@ -package Utils; +package meerkat.destributed_key_generation.utilitis; import com.google.protobuf.Message; -import meerkat.crypto.utilitis.Channel; import meerkat.protobuf.DKGMessages; import java.util.Queue; @@ -76,13 +75,17 @@ public class ChannelImpl implements Channel { } } - @Override - public void registerReceiverCallback(final ReceiverCallback callback) { + public void stop(){ try{ receiverThread.interrupt(); }catch (Exception e){ //do nothing } + } + + @Override + public void registerReceiverCallback(final ReceiverCallback callback) { + stop(); receiverThread = new Thread(new Runnable() { @Override public void run() { diff --git a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java similarity index 82% rename from destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java rename to destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java index 4521fcd..4648598 100644 --- a/destributed-key-generation/src/test/java/Utils/GenerateRandomPolynomial.java +++ b/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java @@ -1,31 +1,30 @@ -package Utils; - -import meerkat.crypto.concrete.secret_shring.shamir.Polynomial; -import meerkat.crypto.utilitis.Arithmetic; -import meerkat.crypto.utilitis.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 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 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 loadedCertificates = new HashMap<>(); - - /** - * Signature currently loaded (will be used in calls to {@link #verify()}). - */ - ByteString loadedSignature = null; - - ByteString loadedSigningKeyId = null; - - /** - * The actual signing implementation. (used for both signing and verifying) - */ - java.security.Signature signer; - - /** - * The currently loaded signing key. - */ - PrivateKey loadedSigningKey; - - - /** - * Compute a fingerprint of a cert as a SHA256 hash. - * - * @param cert - * @return - */ - public ByteString computeCertificateFingerprint(Certificate cert) { - try { - certDigest.reset(); - byte[] data = cert.getEncoded(); - certDigest.update(data); - return ByteString.copyFrom(certDigest.digest()); - } catch (CertificateEncodingException e) { - // Shouldn't happen - logger.error("Certificate encoding error", e); - throw new RuntimeException("Certificate encoding error", e); - } - - } - - public ECDSASignature(java.security.Signature signer) { - this.signer = signer; - } - - public ECDSASignature() { - try { - this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - // Should never happen - logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e); - } - } - - @Override - public void loadVerificationCertificates(InputStream certStream) - throws CertificateException { - CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509); - Collection certs = certificateFactory.generateCertificates(certStream); - for (Certificate cert : certs) { - // Just checking - if (!(cert instanceof X509Certificate)) { - logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName()); - continue; - } - ByteString keyId = computeCertificateFingerprint(cert); - loadedCertificates.put(keyId, cert); - } - } - - @Override - public void clearVerificationCertificates() { - loadedCertificates.clear(); - } - - - /** - * Add the list of messages to the stream that is being verified/signed. - * Messages are prepended with their length in 32-bit big-endian format. - * - * @param msg - * @throws SignatureException - */ - @Override - public void updateContent(Message msg) throws SignatureException { - assert msg != null; - - lenBuf.clear(); - lenBuf.putInt(msg.getSerializedSize()); - lenBuf.flip(); - signer.update(lenBuf); - signer.update(msg.toByteString().asReadOnlyByteBuffer()); - } - - public void updateContent(InputStream in) throws IOException, SignatureException { - ByteString inStr = ByteString.readFrom(in); - signer.update(inStr.asReadOnlyByteBuffer()); - } - - @Override - public Signature sign() throws SignatureException { - Signature.Builder sig = Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setData(ByteString.copyFrom(signer.sign())); - sig.setSignerId(loadedSigningKeyId); - return sig.build(); - } - - @Override - public void initVerify(Signature sig) - throws CertificateException, InvalidKeyException { - Certificate cert = loadedCertificates.get(sig.getSignerId()); - if (cert == null) { - logger.warn("No certificate loaded for ID {}!", sig.getSignerId()); - throw new CertificateException("No certificate loaded for " + sig.getSignerId()); - } - signer.initVerify(cert.getPublicKey()); - loadedSignature = sig.getData(); - loadedSigningKeyId = null; - } - - @Override - public boolean verify() { - try { - return signer.verify(loadedSignature.toByteArray()); - } catch (SignatureException e) { - // Happens only if signature is invalid! - logger.error("Signature exception", e); - return false; - } - } - - /** - * Utility method to more easily deal with simple password-protected files. - * - * @param password - * @return - */ - public CallbackHandler getFixedPasswordHandler(final char[] password) { - return new CallbackHandler() { - @Override - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof PasswordCallback) { - PasswordCallback passwordCallback = (PasswordCallback) callback; - logger.debug("Requested password ({})", passwordCallback.getPrompt()); - passwordCallback.setPassword(password); - } - } - - } - }; - } - - /** - * Load a keystore from an input stream in PKCS12 format. - * - * @param keyStream - * @param password - * @return - * @throws IOException - * @throws CertificateException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - */ - public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) - throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { - KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); - keyStore.load(keyStream, password); - return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password))); - } - - - /** - * For now we only support PKCS12. - * TODO: Support for PKCS11 as well. - * - * @param keyStoreBuilder - * @throws IOException - * @throws CertificateException - * @throws UnrecoverableKeyException - */ - @Override - public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) - throws IOException, CertificateException, UnrecoverableKeyException { - try { - - KeyStore keyStore = keyStoreBuilder.getKeyStore(); - - // Iterate through all aliases until we find the first privatekey - Enumeration aliases = keyStore.aliases(); - while (aliases.hasMoreElements()) { - String alias = aliases.nextElement(); - logger.trace("Testing keystore entry {}", alias); - - - try { - Certificate cert = keyStore.getCertificate(alias); - logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass()); - - Key key; - - try { - key = keyStore.getKey(alias, null); - } catch (UnrecoverableKeyException e) { - // This might be a keystore that doesn't support callback handlers - // (e.g., Java 8 PKCS12) - // Manually extract password using callback handler - char[] password = null; - KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias); - - if (prot instanceof KeyStore.PasswordProtection) { - password = ((KeyStore.PasswordProtection) prot).getPassword(); - } else if (prot instanceof KeyStore.CallbackHandlerProtection) { - PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false); - Callback[] callbacks = { callback }; - try { - ((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks); - password = callback.getPassword(); - } catch (UnsupportedCallbackException e1) { - logger.error("PasswordCallback fallback not supported!", e1); - throw new UnrecoverableKeyException("Couldn't use password callback to get key"); - } - } else { - logger.error("Unrecognized protection handler for keystore: {}", prot.getClass()); - throw new UnrecoverableKeyException("Unrecognized protection handler for keystore"); - } - key = keyStore.getKey(alias, password); - } - logger.trace("keystore entry {}, has key type {}", alias, key.getClass()); - if (key instanceof PrivateKey) { - loadedSigningKey = (PrivateKey) key; - loadedSigningKeyId = computeCertificateFingerprint(cert); - signer.initSign(loadedSigningKey); - logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId)); - - return; - } else { - logger.info("Certificate {} in keystore does not have a private key", cert.toString()); - } - } catch(InvalidKeyException e) { - logger.info("Read invalid key", e); - } catch(UnrecoverableEntryException e) { - logger.info("Read unrecoverable entry", e); - } - } - - } catch (KeyStoreException e) { - logger.error("Keystore exception", e); - } catch (NoSuchAlgorithmException e) { - logger.error("NoSuchAlgorithmException exception", e); - throw new CertificateException(e); - } - logger.error("Didn't find valid private key entry in keystore"); - throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!"); - } - - @Override - public ByteString getSignerID() { - return loadedSigningKeyId; - } - - public void clearSigningKey() { - try { - // TODO: Check if this really clears the key from memory - if (loadedSigningKeyId != null) - signer.initSign(null); - loadedSigningKeyId = null; - loadedSigningKey = null; - // Start garbage collection? - } catch (InvalidKeyException e) { - // Do nothing - } - } - - -} +package meerkat.destributed_key_generation.concrete; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.util.*; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto; +import meerkat.util.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.protobuf.Message; + +import meerkat.destributed_key_generation.DigitalSignature; +import meerkat.protobuf.Crypto.Signature; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + + +/** + * Sign and verify digital signatures. + * + * This class is not thread-safe (each thread should have its own instance). + */ +public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature { + final Logger logger = LoggerFactory.getLogger(getClass()); + + final public static String KEYSTORE_TYPE = "PKCS12"; + final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA"; + + SHA256Digest certDigest = new SHA256Digest(); + + /** + * Buffer used to hold length in for hash update + */ + ByteBuffer lenBuf = ByteBuffer.allocate(4); + + + Map loadedCertificates = new HashMap<>(); + + /** + * Signature currently loaded (will be used in calls to {@link #verify()}). + */ + ByteString loadedSignature = null; + + ByteString loadedSigningKeyId = null; + + /** + * The actual signing implementation. (used for both signing and verifying) + */ + java.security.Signature signer; + + /** + * The currently loaded signing key. + */ + PrivateKey loadedSigningKey; + + + /** + * Compute a fingerprint of a cert as a SHA256 hash. + * + * @param cert + * @return + */ + public ByteString computeCertificateFingerprint(Certificate cert) { + try { + certDigest.reset(); + byte[] data = cert.getEncoded(); + certDigest.update(data); + return ByteString.copyFrom(certDigest.digest()); + } catch (CertificateEncodingException e) { + // Shouldn't happen + logger.error("Certificate encoding error", e); + throw new RuntimeException("Certificate encoding error", e); + } + + } + + public ECDSASignature(java.security.Signature signer) { + this.signer = signer; + } + + public ECDSASignature() { + try { + this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + // Should never happen + logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e); + } + } + + @Override + public void loadVerificationCertificates(InputStream certStream) + throws CertificateException { + CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509); + Collection certs = certificateFactory.generateCertificates(certStream); + for (Certificate cert : certs) { + // Just checking + if (!(cert instanceof X509Certificate)) { + logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName()); + continue; + } + ByteString keyId = computeCertificateFingerprint(cert); + loadedCertificates.put(keyId, cert); + } + } + + @Override + public void clearVerificationCertificates() { + loadedCertificates.clear(); + } + + + /** + * Add the list of messages to the stream that is being verified/signed. + * Messages are prepended with their length in 32-bit big-endian format. + * + * @param msg + * @throws SignatureException + */ + @Override + public void updateContent(Message msg) throws SignatureException { + assert msg != null; + + lenBuf.clear(); + lenBuf.putInt(msg.getSerializedSize()); + lenBuf.flip(); + signer.update(lenBuf); + signer.update(msg.toByteString().asReadOnlyByteBuffer()); + } + + public void updateContent(InputStream in) throws IOException, SignatureException { + ByteString inStr = ByteString.readFrom(in); + signer.update(inStr.asReadOnlyByteBuffer()); + } + + @Override + public Signature sign() throws SignatureException { + Signature.Builder sig = Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setData(ByteString.copyFrom(signer.sign())); + sig.setSignerId(loadedSigningKeyId); + return sig.build(); + } + + @Override + public void initVerify(Signature sig) + throws CertificateException, InvalidKeyException { + Certificate cert = loadedCertificates.get(sig.getSignerId()); + if (cert == null) { + logger.warn("No certificate loaded for ID {}!", sig.getSignerId()); + throw new CertificateException("No certificate loaded for " + sig.getSignerId()); + } + signer.initVerify(cert.getPublicKey()); + loadedSignature = sig.getData(); + loadedSigningKeyId = null; + } + + @Override + public boolean verify() { + try { + return signer.verify(loadedSignature.toByteArray()); + } catch (SignatureException e) { + // Happens only if signature is invalid! + logger.error("Signature exception", e); + return false; + } + } + + /** + * Utility method to more easily deal with simple password-protected files. + * + * @param password + * @return + */ + public CallbackHandler getFixedPasswordHandler(final char[] password) { + return new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof PasswordCallback) { + PasswordCallback passwordCallback = (PasswordCallback) callback; + logger.debug("Requested password ({})", passwordCallback.getPrompt()); + passwordCallback.setPassword(password); + } + } + + } + }; + } + + /** + * Load a keystore from an input stream in PKCS12 format. + * + * @param keyStream + * @param password + * @return + * @throws IOException + * @throws CertificateException + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + */ + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) + throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { + KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + keyStore.load(keyStream, password); + return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password))); + } + + + /** + * For now we only support PKCS12. + * TODO: Support for PKCS11 as well. + * + * @param keyStoreBuilder + * @throws IOException + * @throws CertificateException + * @throws UnrecoverableKeyException + */ + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) + throws IOException, CertificateException, UnrecoverableKeyException { + try { + + KeyStore keyStore = keyStoreBuilder.getKeyStore(); + + // Iterate through all aliases until we find the first privatekey + Enumeration aliases = keyStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + logger.trace("Testing keystore entry {}", alias); + + + try { + Certificate cert = keyStore.getCertificate(alias); + logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass()); + + Key key; + + try { + key = keyStore.getKey(alias, null); + } catch (UnrecoverableKeyException e) { + // This might be a keystore that doesn't support callback handlers + // (e.g., Java 8 PKCS12) + // Manually extract password using callback handler + char[] password = null; + KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias); + + if (prot instanceof KeyStore.PasswordProtection) { + password = ((KeyStore.PasswordProtection) prot).getPassword(); + } else if (prot instanceof KeyStore.CallbackHandlerProtection) { + PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false); + Callback[] callbacks = { callback }; + try { + ((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks); + password = callback.getPassword(); + } catch (UnsupportedCallbackException e1) { + logger.error("PasswordCallback fallback not supported!", e1); + throw new UnrecoverableKeyException("Couldn't use password callback to get key"); + } + } else { + logger.error("Unrecognized protection handler for keystore: {}", prot.getClass()); + throw new UnrecoverableKeyException("Unrecognized protection handler for keystore"); + } + key = keyStore.getKey(alias, password); + } + logger.trace("keystore entry {}, has key type {}", alias, key.getClass()); + if (key instanceof PrivateKey) { + loadedSigningKey = (PrivateKey) key; + loadedSigningKeyId = computeCertificateFingerprint(cert); + signer.initSign(loadedSigningKey); + logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId)); + + return; + } else { + logger.info("Certificate {} in keystore does not have a private key", cert.toString()); + } + } catch(InvalidKeyException e) { + logger.info("Read invalid key", e); + } catch(UnrecoverableEntryException e) { + logger.info("Read unrecoverable entry", e); + } + } + + } catch (KeyStoreException e) { + logger.error("Keystore exception", e); + } catch (NoSuchAlgorithmException e) { + logger.error("NoSuchAlgorithmException exception", e); + throw new CertificateException(e); + } + logger.error("Didn't find valid private key entry in keystore"); + throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!"); + } + + @Override + public ByteString getSignerID() { + return loadedSigningKeyId; + } + + public void clearSigningKey() { + try { + // TODO: Check if this really clears the key from memory + if (loadedSigningKeyId != null) + signer.initSign(null); + loadedSigningKeyId = null; + loadedSigningKey = null; + // Start garbage collection? + } catch (InvalidKeyException e) { + // Do nothing + } + } + + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java similarity index 96% rename from meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java index 05447c9..973b3c7 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java @@ -1,135 +1,135 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.Encryption; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.crypto.params.ECKeyParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.crypto.util.PublicKeyFactory; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; -import org.bouncycastle.util.BigIntegers; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.util.PRGRandom; -import org.factcenter.qilin.util.Pair; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.spec.*; -import java.util.Random; - -/** - * Created by talm on 17/11/15. - */ -public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { - final Logger logger = LoggerFactory.getLogger(getClass()); - - public final static String KEY_ALGORITHM = "ECDH"; - - /** - * The Qilin format El-Gamal public key - */ - ECElGamal.PK elGamalPK; - - ECCurve curve; - - ECGroup group; - - public ECGroup getGroup() { return group; } - - public ECElGamal.PK getElGamalPK() { - return elGamalPK; - } - - public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException { - AsymmetricKeyParameter keyParam; - - try { - keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray()); - } catch (IOException e) { - // Shouldn't every happen - logger.error("Invalid Public Key Encoding", e); - throw new InvalidKeySpecException("Invalid Public Key Encoding", e); - } - - if (!(keyParam instanceof ECPublicKeyParameters)) { - logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass()); - throw new InvalidKeySpecException("Not a valid EC public key!"); - } - - ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters(); - ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(), - params.getSeed()); - - curve = params.getCurve(); - group = new ECGroup(ecParams); - - elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); - } - - - @Override - public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { - - // We write the message using writeDelimited to so the length gets prepended. - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - plaintext.writeDelimitedTo(out); - } catch (IOException e) { - logger.error("Should never happen!", e); - throw new RuntimeException("Error in ByteArrayOutputStream!", e); - } - byte[] msg = out.toByteArray(); - ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg)); - - BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); - Pair cipherText = elGamalPK.encrypt(encodedMsg, rndInt); - ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() - .setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) - .setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) - .build(); - - return Crypto.RerandomizableEncryptedMessage.newBuilder() - .setData(encodedCipherText.toByteString()) - .build(); - } - - @Override - public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { - BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); - Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); - ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); - - Pair originalCipher = new Pair( - curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), - curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); - Pair newCipher = elGamalPK.add(originalCipher, randomizer); - - return Crypto.RerandomizableEncryptedMessage.newBuilder() - .setData( - ConcreteCrypto.ElGamalCiphertext.newBuilder() - .setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) - .setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) - .build().toByteString() - ).build(); - } - - @Override - public Crypto.EncryptionRandomness generateRandomness(Random rand) { - BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand); - Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder() - .setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build(); - - return retval; - } -} +package meerkat.destributed_key_generation.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.destributed_key_generation.Encryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.util.PRGRandom; +import org.factcenter.qilin.util.Pair; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.spec.*; +import java.util.Random; + +/** + * Created by talm on 17/11/15. + */ +public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { + final Logger logger = LoggerFactory.getLogger(getClass()); + + public final static String KEY_ALGORITHM = "ECDH"; + + /** + * The Qilin format El-Gamal public key + */ + ECElGamal.PK elGamalPK; + + ECCurve curve; + + ECGroup group; + + public ECGroup getGroup() { return group; } + + public ECElGamal.PK getElGamalPK() { + return elGamalPK; + } + + public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException { + AsymmetricKeyParameter keyParam; + + try { + keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray()); + } catch (IOException e) { + // Shouldn't every happen + logger.error("Invalid Public Key Encoding", e); + throw new InvalidKeySpecException("Invalid Public Key Encoding", e); + } + + if (!(keyParam instanceof ECPublicKeyParameters)) { + logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass()); + throw new InvalidKeySpecException("Not a valid EC public key!"); + } + + ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters(); + ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(), + params.getSeed()); + + curve = params.getCurve(); + group = new ECGroup(ecParams); + + elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); + } + + + @Override + public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { + + // We write the message using writeDelimited to so the length gets prepended. + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + plaintext.writeDelimitedTo(out); + } catch (IOException e) { + logger.error("Should never happen!", e); + throw new RuntimeException("Error in ByteArrayOutputStream!", e); + } + byte[] msg = out.toByteArray(); + ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg)); + + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair cipherText = elGamalPK.encrypt(encodedMsg, rndInt); + ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) + .setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) + .build(); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData(encodedCipherText.toByteString()) + .build(); + } + + @Override + public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); + ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); + + Pair originalCipher = new Pair( + curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), + curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); + Pair newCipher = elGamalPK.add(originalCipher, randomizer); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData( + ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) + .setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) + .build().toByteString() + ).build(); + } + + @Override + public Crypto.EncryptionRandomness generateRandomness(Random rand) { + BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand); + Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder() + .setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build(); + + return retval; + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java similarity index 92% rename from meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java index ca09689..7efc793 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java @@ -1,43 +1,43 @@ -package meerkat.crypto.concrete; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.security.Provider; -import java.security.Security; - -/** - * A class that performs required crypto setup - */ -public class GlobalCryptoSetup { - final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); - - static boolean loadedBouncyCastle = false; - static Provider bouncyCastleProvider; - - public static boolean hasSecp256k1Curve() { - // For now we just check if the java version is at least 8 - String[] version = System.getProperty("java.version").split("\\."); - int major = Integer.parseInt(version[0]); - int minor = Integer.parseInt(version[1]); - return ((major > 1) || ((major > 0) && (minor > 7))); - } - - public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } - - public static synchronized void doSetup() { - if (bouncyCastleProvider == null) { - bouncyCastleProvider = new BouncyCastleProvider(); - // Make bouncycastle our default provider if we're running on a JVM version < 8 - // (earlier version don't support the EC curve we use for signatures) - if (!hasSecp256k1Curve() && !loadedBouncyCastle) { - loadedBouncyCastle = true; - Security.insertProviderAt(bouncyCastleProvider, 1); - logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve"); - } - } - } - - public GlobalCryptoSetup() { doSetup(); } -} +package meerkat.destributed_key_generation.concrete; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.Provider; +import java.security.Security; + +/** + * A class that performs required destributed_key_generation setup + */ +public class GlobalCryptoSetup { + final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); + + static boolean loadedBouncyCastle = false; + static Provider bouncyCastleProvider; + + public static boolean hasSecp256k1Curve() { + // For now we just check if the java version is at least 8 + String[] version = System.getProperty("java.version").split("\\."); + int major = Integer.parseInt(version[0]); + int minor = Integer.parseInt(version[1]); + return ((major > 1) || ((major > 0) && (minor > 7))); + } + + public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } + + public static synchronized void doSetup() { + if (bouncyCastleProvider == null) { + bouncyCastleProvider = new BouncyCastleProvider(); + // Make bouncycastle our default provider if we're running on a JVM version < 8 + // (earlier version don't support the EC curve we use for signatures) + if (!hasSecp256k1Curve() && !loadedBouncyCastle) { + loadedBouncyCastle = true; + Security.insertProviderAt(bouncyCastleProvider, 1); + logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve"); + } + } + } + + public GlobalCryptoSetup() { doSetup(); } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java similarity index 93% rename from meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java index 784da82..6c2fce2 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java @@ -1,96 +1,96 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.Message; -import meerkat.crypto.Digest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * Created by talm on 11/9/15. - */ -public class SHA256Digest extends GlobalCryptoSetup implements Digest { - final Logger logger = LoggerFactory.getLogger(getClass()); - public static final String SHA256 = "SHA-256"; - - MessageDigest hash; - - /** - * Used to convert length to bytes in proper order. - */ - ByteBuffer lenBuf = ByteBuffer.allocate(4); - - /** - * Instantiate with a specified algorithm. - * @param algorithm - * @throws NoSuchAlgorithmException - */ - public SHA256Digest(String algorithm) throws NoSuchAlgorithmException { - hash = MessageDigest.getInstance(algorithm); - } - - /** - * Instantiate with the default (SHA-256) algorithm - */ - public SHA256Digest() { this(true); } - - - /**SHA - * Instantiate with the default (SHA-256) algorithm, - * or create an empty class (for cloning) - */ - private SHA256Digest(boolean initHash) { - if (initHash) { - try { - hash = MessageDigest.getInstance(SHA256); - } catch (NoSuchAlgorithmException e) { - // Should never happen! - logger.error("Couldn't find default {} algorhtm: {}", SHA256, e); - assert false; - } - } - } - - @Override - public byte[] digest() { - return hash.digest(); - } - - @Override - public void update(Message msg) { - - lenBuf.clear(); - lenBuf.putInt(msg.getSerializedSize()); - lenBuf.flip(); - hash.update(lenBuf); - hash.update(msg.toByteString().asReadOnlyByteBuffer()); - } - - final public void update(ByteString msg) { - hash.update(msg.asReadOnlyByteBuffer()); - } - - final public void update(byte[] msg) { - hash.update(msg); - } - - final public void update(ByteBuffer msg) { - hash.update(msg); - } - - @Override - public void reset() { - hash.reset(); - } - - @Override - public SHA256Digest clone() throws CloneNotSupportedException { - SHA256Digest copy = new SHA256Digest(false); - copy.hash = (MessageDigest) hash.clone(); - return copy; - } -} +package meerkat.destributed_key_generation.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.destributed_key_generation.Digest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Created by talm on 11/9/15. + */ +public class SHA256Digest extends GlobalCryptoSetup implements Digest { + final Logger logger = LoggerFactory.getLogger(getClass()); + public static final String SHA256 = "SHA-256"; + + MessageDigest hash; + + /** + * Used to convert length to bytes in proper order. + */ + ByteBuffer lenBuf = ByteBuffer.allocate(4); + + /** + * Instantiate with a specified algorithm. + * @param algorithm + * @throws NoSuchAlgorithmException + */ + public SHA256Digest(String algorithm) throws NoSuchAlgorithmException { + hash = MessageDigest.getInstance(algorithm); + } + + /** + * Instantiate with the default (SHA-256) algorithm + */ + public SHA256Digest() { this(true); } + + + /**SHA + * Instantiate with the default (SHA-256) algorithm, + * or create an empty class (for cloning) + */ + private SHA256Digest(boolean initHash) { + if (initHash) { + try { + hash = MessageDigest.getInstance(SHA256); + } catch (NoSuchAlgorithmException e) { + // Should never happen! + logger.error("Couldn't find default {} algorhtm: {}", SHA256, e); + assert false; + } + } + } + + @Override + public byte[] digest() { + return hash.digest(); + } + + @Override + public void update(Message msg) { + + lenBuf.clear(); + lenBuf.putInt(msg.getSerializedSize()); + lenBuf.flip(); + hash.update(lenBuf); + hash.update(msg.toByteString().asReadOnlyByteBuffer()); + } + + final public void update(ByteString msg) { + hash.update(msg.asReadOnlyByteBuffer()); + } + + final public void update(byte[] msg) { + hash.update(msg); + } + + final public void update(ByteBuffer msg) { + hash.update(msg); + } + + @Override + public void reset() { + hash.reset(); + } + + @Override + public SHA256Digest clone() throws CloneNotSupportedException { + SHA256Digest copy = new SHA256Digest(false); + copy.hash = (MessageDigest) hash.clone(); + return copy; + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java similarity index 93% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java index 438cb51..aa63aeb 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java @@ -1,18 +1,18 @@ -package meerkat.crypto.mixnet; - -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -/** - * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. - */ -public interface Mix2ZeroKnowledgeProver { - public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - boolean switched, - Crypto.EncryptionRandomness r1, - Crypto.EncryptionRandomness r2); - -} +package meerkat.destributed_key_generation.mixnet; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. + */ +public interface Mix2ZeroKnowledgeProver { + public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + boolean switched, + Crypto.EncryptionRandomness r1, + Crypto.EncryptionRandomness r2); + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java similarity index 91% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java index 7fa845c..6faf0ca 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java @@ -1,23 +1,23 @@ -package meerkat.crypto.mixnet; - -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; - -/** - * Verify the two-ciphertext mix proof - */ -public interface Mix2ZeroKnowledgeVerifier { - /** - * Return true iff the proof is valid. - * @param in1 - * @param in2 - * @param out1 - * @param out2 - * @return - */ - boolean verify(Crypto.RerandomizableEncryptedMessage in1, - Crypto.RerandomizableEncryptedMessage in2, - Crypto.RerandomizableEncryptedMessage out1, - Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof); -} +package meerkat.destributed_key_generation.mixnet; + +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; + +/** + * Verify the two-ciphertext mix proof + */ +public interface Mix2ZeroKnowledgeVerifier { + /** + * Return true iff the proof is valid. + * @param in1 + * @param in2 + * @param out1 + * @param out2 + * @return + */ + boolean verify(Crypto.RerandomizableEncryptedMessage in1, + Crypto.RerandomizableEncryptedMessage in2, + Crypto.RerandomizableEncryptedMessage out1, + Crypto.RerandomizableEncryptedMessage out2, + Mixing.ZeroKnowledgeProof proof); +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java similarity index 79% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java index 0be60c3..2b6d3e8 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java @@ -1,11 +1,11 @@ -package meerkat.crypto.mixnet; - -import java.util.List; -import static meerkat.protobuf.Voting.*; - -/** - * Created by talm on 25/10/15. - */ -public interface Mixer { - public List mix(List ballots); -} +package meerkat.destributed_key_generation.mixnet; + +import java.util.List; +import static meerkat.protobuf.Voting.*; + +/** + * Created by talm on 25/10/15. + */ +public interface Mixer { + public List mix(List ballots); +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java similarity index 56% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java index a131a65..ded66c5 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java @@ -1,7 +1,7 @@ -package meerkat.crypto.mixnet; - -/** - * Created by talm on 25/10/15. - */ -public class Trustee { -} +package meerkat.destributed_key_generation.mixnet; + +/** + * Created by talm on 25/10/15. + */ +public class Trustee { +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java similarity index 56% rename from meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java rename to meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java index 809678e..18271ed 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java +++ b/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java @@ -1,7 +1,7 @@ -package meerkat.crypto.mixnet; - -/** - * Created by talm on 25/10/15. - */ -public class Verifier { -} +package meerkat.destributed_key_generation.mixnet; + +/** + * Created by talm on 25/10/15. + */ +public class Verifier { +} diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java similarity index 91% rename from meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java rename to meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java index cefc1b2..86ae311 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java @@ -1,50 +1,49 @@ -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; - -import java.math.BigInteger; -import static org.junit.Assert.*; - -/** - * Created by talm on 12/11/15. - */ -public class ECDSADeterministicSignatureTest extends ECDSASignatureTest { - - @Override - protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); } - - - /** - * Make sure signatures don't vary - */ - @Test - public void testDeterministicSigning() throws Exception { - loadSigningKeys(); - - - for (int i = 0; i < REPEAT_COUNT; ++i) { - BigInteger rawMsg = new BigInteger(50, rand); - Message msg = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; - - signer.updateContent(msg); - sigs[0] = signer.sign(); - byte[] canonicalSig = sigs[0].toByteArray(); - - for (int j = 1; j < sigs.length; ++j) { - signer.updateContent(msg); - sigs[j] = signer.sign(); - - byte[] newSig = sigs[j].toByteArray(); - - assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig); - } - } - } -} +package meerkat.destributed_key_generation.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; + +import meerkat.protobuf.Crypto; +import org.junit.Test; + +import java.math.BigInteger; +import static org.junit.Assert.*; + +/** + * Created by talm on 12/11/15. + */ +public class ECDSADeterministicSignatureTest extends ECDSASignatureTest { + + @Override + protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); } + + + /** + * Make sure signatures don't vary + */ + @Test + public void testDeterministicSigning() throws Exception { + loadSigningKeys(); + + + for (int i = 0; i < REPEAT_COUNT; ++i) { + BigInteger rawMsg = new BigInteger(50, rand); + Message msg = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; + + signer.updateContent(msg); + sigs[0] = signer.sign(); + byte[] canonicalSig = sigs[0].toByteArray(); + + for (int j = 1; j < sigs.length; ++j) { + signer.updateContent(msg); + sigs[j] = signer.sign(); + + byte[] newSig = sigs[j].toByteArray(); + + assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig); + } + } + } +} diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java similarity index 96% rename from meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java rename to meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java index 327292a..9e90cce 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java @@ -1,220 +1,219 @@ -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; - -import java.io.InputStream; -import java.math.BigInteger; -import java.security.KeyStore; -import java.util.Random; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Created by talm on 12/11/15. - */ -public class ECDSASignatureTest { - public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; - public static String KEYFILE_PASSWORD = "secret"; - - public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; - public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der"; - - public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt"; - public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig"; - - public static String HELLO_WORLD = "hello world!"; - - public final static int REPEAT_COUNT = 10; - - Random rand = new Random(0); - - protected ECDSASignature signer; - - protected ECDSASignature getSigner() { return new ECDSASignature(); } - - @Before - public void setup() throws Exception { - signer = getSigner(); - } - - @Test - public void loadSignatureKey() throws Exception { - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD.toCharArray(); - - KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); - signer.loadSigningCertificate(keyStore); - keyStream.close(); - } - - @Test - public void loadPEMVerificationKey() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - } - - @Test - public void loadDERVerificationKey() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - } - - - @Test - public void verifyValidSig() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - sig.setData(ByteString.readFrom(sigStream)); - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertTrue("Signature did not verify!", signer.verify()); - } - - @Test - public void verifyInvalidSig() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - byte[] sigData = ByteString.readFrom(sigStream).toByteArray(); - ++sigData[0]; - - sig.setData(ByteString.copyFrom(sigData)); - - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertFalse("Bad Signature passed verification!", signer.verify()); - } - - - @Test - public void verifyInvalidMsg() throws Exception { - InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); - InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); - InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); - - signer.loadVerificationCertificates(certStream); - certStream.close(); - - Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); - sig.setType(Crypto.SignatureType.ECDSA); - sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); - sig.setData(ByteString.readFrom(sigStream)); - byte[] msgData = ByteString.readFrom(msgStream).toByteArray(); - ++msgData[0]; - - Crypto.Signature builtSig = sig.build(); - signer.initVerify(builtSig); - signer.updateContent(msgStream); - assertFalse("Signature doesn't match message but passed verification!", signer.verify()); - } - - - - protected void loadSigningKeys() throws Exception { - InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); - char[] password = KEYFILE_PASSWORD.toCharArray(); - - KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); - signer.loadSigningCertificate(keyStore); - } - - @Test - public void signAndVerify() throws Exception { - loadSigningKeys(); - - BigInteger rawMsg = new BigInteger(50, rand); - Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - - signer.updateContent(usMsg); - Crypto.Signature sig = signer.sign(); - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - signer.initVerify(sig); - signer.updateContent(usMsg); - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - - @Test - public void signMultipleAndVerify() throws Exception { - loadSigningKeys(); - - Message[] msgs = new Message[REPEAT_COUNT]; - for (int i = 0; i < msgs.length; ++i) { - - BigInteger rawMsg = new BigInteger(50, rand); - msgs[i] = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - signer.updateContent(msgs[i]); - } - - Crypto.Signature sig = signer.sign(); - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - signer.initVerify(sig); - for (int i = 0; i < msgs.length; ++i) { - signer.updateContent(msgs[i]); - } - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - @Test - public void multipleSignAndVerify() throws Exception { - loadSigningKeys(); - - Message[] msgs = new Message[REPEAT_COUNT]; - Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; - for (int i = 0; i < msgs.length; ++i) { - BigInteger rawMsg = new BigInteger(50, rand); - msgs[i] = Crypto.BigInteger.newBuilder() - .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); - signer.updateContent(msgs[i]); - sigs[i] = signer.sign(); - } - - signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - - for (int i = 0; i < msgs.length; ++i) { - signer.initVerify(sigs[i]); - signer.updateContent(msgs[i]); - assertTrue("Couldn't verify signature on ", signer.verify()); - } - - } - - - -} +package meerkat.destributed_key_generation.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.protobuf.Crypto; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; +import java.math.BigInteger; +import java.security.KeyStore; +import java.util.Random; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Created by talm on 12/11/15. + */ +public class ECDSASignatureTest { + public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + public static String KEYFILE_PASSWORD = "secret"; + + public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der"; + + public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt"; + public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig"; + + public static String HELLO_WORLD = "hello world!"; + + public final static int REPEAT_COUNT = 10; + + Random rand = new Random(0); + + protected ECDSASignature signer; + + protected ECDSASignature getSigner() { return new ECDSASignature(); } + + @Before + public void setup() throws Exception { + signer = getSigner(); + } + + @Test + public void loadSignatureKey() throws Exception { + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD.toCharArray(); + + KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); + signer.loadSigningCertificate(keyStore); + keyStream.close(); + } + + @Test + public void loadPEMVerificationKey() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + } + + @Test + public void loadDERVerificationKey() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + } + + + @Test + public void verifyValidSig() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + sig.setData(ByteString.readFrom(sigStream)); + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertTrue("Signature did not verify!", signer.verify()); + } + + @Test + public void verifyInvalidSig() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + byte[] sigData = ByteString.readFrom(sigStream).toByteArray(); + ++sigData[0]; + + sig.setData(ByteString.copyFrom(sigData)); + + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertFalse("Bad Signature passed verification!", signer.verify()); + } + + + @Test + public void verifyInvalidMsg() throws Exception { + InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE); + InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE); + InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE); + + signer.loadVerificationCertificates(certStream); + certStream.close(); + + Crypto.Signature.Builder sig = Crypto.Signature.newBuilder(); + sig.setType(Crypto.SignatureType.ECDSA); + sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey()); + sig.setData(ByteString.readFrom(sigStream)); + byte[] msgData = ByteString.readFrom(msgStream).toByteArray(); + ++msgData[0]; + + Crypto.Signature builtSig = sig.build(); + signer.initVerify(builtSig); + signer.updateContent(msgStream); + assertFalse("Signature doesn't match message but passed verification!", signer.verify()); + } + + + + protected void loadSigningKeys() throws Exception { + InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD.toCharArray(); + + KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password); + signer.loadSigningCertificate(keyStore); + } + + @Test + public void signAndVerify() throws Exception { + loadSigningKeys(); + + BigInteger rawMsg = new BigInteger(50, rand); + Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + + signer.updateContent(usMsg); + Crypto.Signature sig = signer.sign(); + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + signer.initVerify(sig); + signer.updateContent(usMsg); + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + + @Test + public void signMultipleAndVerify() throws Exception { + loadSigningKeys(); + + Message[] msgs = new Message[REPEAT_COUNT]; + for (int i = 0; i < msgs.length; ++i) { + + BigInteger rawMsg = new BigInteger(50, rand); + msgs[i] = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + signer.updateContent(msgs[i]); + } + + Crypto.Signature sig = signer.sign(); + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + signer.initVerify(sig); + for (int i = 0; i < msgs.length; ++i) { + signer.updateContent(msgs[i]); + } + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + @Test + public void multipleSignAndVerify() throws Exception { + loadSigningKeys(); + + Message[] msgs = new Message[REPEAT_COUNT]; + Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT]; + for (int i = 0; i < msgs.length; ++i) { + BigInteger rawMsg = new BigInteger(50, rand); + msgs[i] = Crypto.BigInteger.newBuilder() + .setData(ByteString.copyFrom(rawMsg.toByteArray())).build(); + signer.updateContent(msgs[i]); + sigs[i] = signer.sign(); + } + + signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + + for (int i = 0; i < msgs.length; ++i) { + signer.initVerify(sigs[i]); + signer.updateContent(msgs[i]); + assertTrue("Couldn't verify signature on ", signer.verify()); + } + + } + + + +} diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java similarity index 96% rename from meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java rename to meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java index a911b96..b09fbce 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java +++ b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java @@ -1,122 +1,122 @@ -package meerkat.crypto.concrete; - -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Voting; -import org.bouncycastle.math.ec.ECPoint; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.util.Pair; - -import java.math.BigInteger; -import java.util.Random; - -import static org.junit.Assert.*; - -/** - * Test class for {@link ECElGamalEncryption} - */ -public class ECElGamalEncryptionTest { - final Logger logger = LoggerFactory.getLogger(getClass()); - /** - * Number of times to repeat probabilistic tests. - */ - public final static int CONFIDENCE = 10; - - Random rand = new Random(0); // Insecure deterministic random for testing. - - ECElGamal.SK key; - ECGroup group; - ECElGamalEncryption enc; - ConcreteCrypto.ElGamalPublicKey serializedPk; - - - @Before - public void setup() throws Exception { - group = new ECGroup("secp256k1"); - BigInteger sk = ECElGamal.generateSecretKey(group, rand); - key = new ECElGamal.SK(group, sk); - serializedPk = ECElGamalUtils.serializePk(group, key); - - - enc = new ECElGamalEncryption(); - - enc.init(serializedPk); - } - - - Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { - Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); - ballot.setSerialNumber(rand.nextInt(1000000)); - for (int i = 0; i < numQuestions; ++i) { - Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); - for (int j = 0; j < numAnswers; ++j) { - answers.addAnswer(rand.nextInt(maxAnswer)); - } - } - return ballot.build(); - } - - /** - * Testing just the key management - * @throws Exception - */ - @Test - public void testPkSerialization() throws Exception { - ECElGamal.PK pk = enc.getElGamalPK(); - - ECPoint point = enc.getGroup().sample(rand); - Pair cipher = pk.encrypt(point, pk.getRandom(rand)); - - ECPoint decrypted = key.decrypt(cipher); - - assertEquals("Decrypted value not equal to encrypted value!", point, decrypted); - } - - @Test - public void testEncryption() throws Exception { - for (int i = 0; i < CONFIDENCE; ++i) { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) { - logger.error("Test Message too big (|msg|={} > max={}), expect failure.", - msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength()); - } - - Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand)); - - Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText); - - assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted); - } - } - - @Test - public void testRerandomizeModifiesCiphertext() throws Exception { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand)); - Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand)); - assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2); - } - - @Test - public void testRerandomizePreservesPlaintext() throws Exception { - for (int i = 0; i < CONFIDENCE; ++i) { - Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. - - Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand)); - Crypto.RerandomizableEncryptedMessage cipher2 = cipher; - for (int j = 0; j < CONFIDENCE; ++j) - cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand)); - - Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, - cipher2); - - assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted); - } - } -} - +package meerkat.destributed_key_generation.concrete; + +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Voting; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.util.Pair; + +import java.math.BigInteger; +import java.util.Random; + +import static org.junit.Assert.*; + +/** + * Test class for {@link ECElGamalEncryption} + */ +public class ECElGamalEncryptionTest { + final Logger logger = LoggerFactory.getLogger(getClass()); + /** + * Number of times to repeat probabilistic tests. + */ + public final static int CONFIDENCE = 10; + + Random rand = new Random(0); // Insecure deterministic random for testing. + + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + + + @Before + public void setup() throws Exception { + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = ECElGamalUtils.serializePk(group, key); + + + enc = new ECElGamalEncryption(); + + enc.init(serializedPk); + } + + + Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { + Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); + ballot.setSerialNumber(rand.nextInt(1000000)); + for (int i = 0; i < numQuestions; ++i) { + Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); + for (int j = 0; j < numAnswers; ++j) { + answers.addAnswer(rand.nextInt(maxAnswer)); + } + } + return ballot.build(); + } + + /** + * Testing just the key management + * @throws Exception + */ + @Test + public void testPkSerialization() throws Exception { + ECElGamal.PK pk = enc.getElGamalPK(); + + ECPoint point = enc.getGroup().sample(rand); + Pair cipher = pk.encrypt(point, pk.getRandom(rand)); + + ECPoint decrypted = key.decrypt(cipher); + + assertEquals("Decrypted value not equal to encrypted value!", point, decrypted); + } + + @Test + public void testEncryption() throws Exception { + for (int i = 0; i < CONFIDENCE; ++i) { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) { + logger.error("Test Message too big (|msg|={} > max={}), expect failure.", + msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength()); + } + + Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand)); + + Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText); + + assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted); + } + } + + @Test + public void testRerandomizeModifiesCiphertext() throws Exception { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand)); + assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2); + } + + @Test + public void testRerandomizePreservesPlaintext() throws Exception { + for (int i = 0; i < CONFIDENCE; ++i) { + Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + + Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage cipher2 = cipher; + for (int j = 0; j < CONFIDENCE; ++j) + cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand)); + + Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, + cipher2); + + assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted); + } + } +} + diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java similarity index 96% rename from meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java rename to meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java index f83aaea..9b5de78 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java @@ -1,89 +1,89 @@ -package meerkat.crypto.concrete; - -import com.google.protobuf.ByteString; -import com.google.protobuf.GeneratedMessage; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.ConcreteCrypto; -import meerkat.protobuf.Crypto; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECPoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.factcenter.qilin.primitives.concrete.ECElGamal; -import org.factcenter.qilin.primitives.concrete.ECGroup; -import org.factcenter.qilin.primitives.generic.ElGamal; -import org.factcenter.qilin.util.Pair; - -import java.io.ByteArrayInputStream; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; - -/** - * utilities for ECElgamal - */ -public class ECElGamalUtils { - final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); - - public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; - - /** - * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} - * @param pk - * @return - */ - public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { - ECPoint pkPoint = pk.getPK(); - ECParameterSpec params = group.getCurveParams(); - - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); - - try { - KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); - PublicKey javaPk = fact.generatePublic(pubKeySpec); - ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() - .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); - - return serializedPk; - } catch (NoSuchAlgorithmException|InvalidKeySpecException e) { - logger.error("Should never happen!", e); - throw new RuntimeException("Error converting public key!", e); - } - } - - /** - * Standard (non-threshold) decryption for testing purposes. - * @param secretKey - * @return - */ - public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) - throws InvalidProtocolBufferException { - ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); - ByteString c1encoded = cipherText.getC1(); - ByteString c2encoded = cipherText.getC2(); - - ECPoint c1 = group.decode(c1encoded.toByteArray()); - ECPoint c2 = group.decode(c2encoded.toByteArray()); - - ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); - - byte[] plaintext = group.injectiveDecode(plaintextEncoded); - - ByteArrayInputStream in = new ByteArrayInputStream(plaintext); - - try { - java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); - builder.mergeDelimitedFrom(in); - return plaintextMessageType.cast(builder.build()); - } catch (Exception e) { - logger.error("Error parsing incoming message", e); - throw new InvalidProtocolBufferException("Plaintext protobuf error"); - } - } - -} +package meerkat.destributed_key_generation.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.factcenter.qilin.primitives.concrete.ECElGamal; +import org.factcenter.qilin.primitives.concrete.ECGroup; +import org.factcenter.qilin.primitives.generic.ElGamal; +import org.factcenter.qilin.util.Pair; + +import java.io.ByteArrayInputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; + +/** + * utilities for ECElgamal + */ +public class ECElGamalUtils { + final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (NoSuchAlgorithmException|InvalidKeySpecException e) { + logger.error("Should never happen!", e); + throw new RuntimeException("Error converting public key!", e); + } + } + + /** + * Standard (non-threshold) decryption for testing purposes. + * @param secretKey + * @return + */ + public static T decrypt(Class plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) + throws InvalidProtocolBufferException { + ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); + ByteString c1encoded = cipherText.getC1(); + ByteString c2encoded = cipherText.getC2(); + + ECPoint c1 = group.decode(c1encoded.toByteArray()); + ECPoint c2 = group.decode(c2encoded.toByteArray()); + + ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); + + byte[] plaintext = group.injectiveDecode(plaintextEncoded); + + ByteArrayInputStream in = new ByteArrayInputStream(plaintext); + + try { + java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); + builder.mergeDelimitedFrom(in); + return plaintextMessageType.cast(builder.build()); + } catch (Exception e) { + logger.error("Error parsing incoming message", e); + throw new InvalidProtocolBufferException("Plaintext protobuf error"); + } + } + +} From 857821c0e4d78096048fd2004813f20ed5d277aa Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 11 Apr 2016 12:17:05 +0300 Subject: [PATCH 040/106] Adding one more file to version control --- .../SingleServerQuerySyncWorker.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerQuerySyncWorker.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerQuerySyncWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerQuerySyncWorker.java new file mode 100644 index 0000000..3a9873d --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerQuerySyncWorker.java @@ -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 { + + 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(); + } + + } +} From 07aecd52378872c674999261226ad5406deb3abe Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 11 Apr 2016 12:26:02 +0300 Subject: [PATCH 041/106] TimestampComparator name change --- .../util/{TimeStampComparator.java => TimestampComparator.java} | 1 + 1 file changed, 1 insertion(+) rename meerkat-common/src/main/java/meerkat/util/{TimeStampComparator.java => TimestampComparator.java} (99%) diff --git a/meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java b/meerkat-common/src/main/java/meerkat/util/TimestampComparator.java similarity index 99% rename from meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java rename to meerkat-common/src/main/java/meerkat/util/TimestampComparator.java index 1dc207b..9acdaa6 100644 --- a/meerkat-common/src/main/java/meerkat/util/TimeStampComparator.java +++ b/meerkat-common/src/main/java/meerkat/util/TimestampComparator.java @@ -27,4 +27,5 @@ public class TimestampComparator implements Comparator Date: Mon, 11 Apr 2016 14:13:26 +0300 Subject: [PATCH 042/106] Fixed H2 test time (by using a connection pool) Added same fix to MySQL Fixed and tested H2 SyncQuery --- bulletin-board-server/build.gradle | 1 + .../bulletinboard/sqlserver/H2QueryProvider.java | 10 +++++++--- .../sqlserver/MySQLQueryProvider.java | 14 ++++++++------ .../bulletinboard/H2BulletinBoardServerTest.java | 10 ++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 8d824e7..7e06c1c 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -51,6 +51,7 @@ dependencies { 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.+' diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index a54c2ff..44a55da 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -1,6 +1,7 @@ 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; @@ -61,7 +62,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum"; case INSERT_MSG: - return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,: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" @@ -200,10 +201,13 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider @Override public DataSource getDataSource() { - JdbcDataSource dataSource = new JdbcDataSource(); - dataSource.setURL("jdbc:h2:~/" + dbName); + BasicDataSource dataSource = new BasicDataSource(); + + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUrl("jdbc:h2:~/" + dbName); return dataSource; + } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index f99114e..adf96a4 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -4,6 +4,7 @@ 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; @@ -216,16 +217,17 @@ public class MySQLQueryProvider implements SQLQueryProvider { @Override public DataSource getDataSource() { - MysqlDataSource dataSource = new MysqlDataSource(); - dataSource.setServerName(dbAddress); - dataSource.setPort(dbPort); - dataSource.setDatabaseName(dbName); - dataSource.setUser(username); + BasicDataSource dataSource = new BasicDataSource(); + + dataSource.setDriverClassName("com.mysql.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://" + dbAddress + ":" + dbPort + "/" + dbName); + + dataSource.setUsername(username); dataSource.setPassword(password); - dataSource.setAllowMultiQueries(true); return dataSource; + } @Override diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java index 577c9be..512b4c9 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -140,6 +140,16 @@ public class H2BulletinBoardServerTest { } + @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"); From e904caa74f2c16afa31dddbb3083b0fdeb357f4f Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Mon, 11 Apr 2016 14:21:36 +0300 Subject: [PATCH 043/106] Added certificates to version control --- .../enduser-certs/user3-key-with-password-shh.p12 | Bin 0 -> 857 bytes .../test/resources/certs/enduser-certs/user3.crt | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 meerkat-common/src/test/resources/certs/enduser-certs/user3-key-with-password-shh.p12 create mode 100644 meerkat-common/src/test/resources/certs/enduser-certs/user3.crt diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user3-key-with-password-shh.p12 b/meerkat-common/src/test/resources/certs/enduser-certs/user3-key-with-password-shh.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c62cee15259b04a77890facb4d68a8f99c46c276 GIT binary patch literal 857 zcmXqLVh&|uWHxAGmS^MCYV&CO&dbQoxS)wyfTf9<2Pn*8(8PEjA;q?!iSYtZ=nNAh z1CTn3kYO~CVdH|Dz{AL9z{kSzR{7cIAM3ZyW@6%CXlP=b!M1fz{)!FRvCEt}g&oR2 z&Q$-iW^?Pp<^?v+>zzcxT{8MUmOPuMen0D;vJlra1G)LKtt)5WO?YOfTtCh5Qo_eN z7f%21Wo_Fu-WYSg`?pbUnR!jghRE*Bn`HbpF7CZ0i<0)FNrkHu>suu6XS0}sJu5WtIU3&GL*Kfrqj~+EHKAAtMTgmqFU!6>s zZsyx8&ODJTS`Iu2ln;Bi;)8af#_Z(Qy;J9$yL)ufwbe@|&AcznyGv=gyx)=M9!__h zx1_5bF8X_2xZRgG=9%u1G^cF`WaH)^QcS z%9iPAP-ourGtUiP{lB92+<_&6*W=Xl#GaH@UClG@uYGkc-C*BD_n#&*DJumY89Eq9 z!oA2TV#p)M#gNR9%232m!eD5ijF1vF6k`#&`R>#2rEbxE-Hr=n)&E6!l=%tmGSD?p xG~i@o)#hVnl450G5wUR6{-*U}YFqOeLl(cwPh$CYANt6`u|?0t*kS67=>Xf8Y@GlA literal 0 HcmV?d00001 diff --git a/meerkat-common/src/test/resources/certs/enduser-certs/user3.crt b/meerkat-common/src/test/resources/certs/enduser-certs/user3.crt new file mode 100644 index 0000000..23ee857 --- /dev/null +++ b/meerkat-common/src/test/resources/certs/enduser-certs/user3.crt @@ -0,0 +1,8 @@ +-----BEGIN CERTIFICATE----- +MIIBGjCBw6ADAgECAgEBMAkGByqGSM49BAEwEDEOMAwGA1UEAxMFY2VydDEwHhcN +MTUxMTI4MTEwNDAwWhcNMTYxMTI4MTEwNDAwWjAQMQ4wDAYDVQQDEwVjZXJ0MTBZ +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABLiyFMVWQtFi4fCjOGLDwQcdjyr48Y8j +P+eLEIGMYKKv8bqL3Vchs0iOPoyGH6jxYj2/ShnLSIEuIMPfVgV9kxSjDzANMAsG +A1UdDwQEAwIHgDAJBgcqhkjOPQQBA0cAMEQCIH7R0AWO0AYiHOs+QsHEpWiebFc1 +cyxCKJGkf8KA1KJrAiArCia7PWl0KzaqA0RQC4J0BKp4rZo1PCqKI8DirKQf/Q== +-----END CERTIFICATE----- From 1ec02173e7859a68f25e205888dc8ddafba0ddc9 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Mon, 11 Apr 2016 19:48:36 +0300 Subject: [PATCH 044/106] package renaming and protobuf moves --- .../bulletinboard/BulletinClientWorker.java | 4 ++-- .../SimpleBulletinBoardClient.java | 4 ++-- .../ThreadedBulletinBoardClient.java | 4 ++-- .../sqlserver/BulletinBoardSQLServer.java | 4 ++-- .../GenericBulletinBoardServerTest.java | 2 +- .../build.gradle | 0 .../meerkat/crypto/dkg/comm}/MailHandler.java | 4 ++-- .../crypto/dkg/comm}/MessageHandler.java | 2 +- .../crypto/dkg/feldman}/MailHandler.java | 6 ++--- .../meerkat/crypto/dkg/feldman}/Party.java | 4 ++-- .../meerkat/crypto/dkg/feldman}/Protocol.java | 8 +++---- .../meerkat/crypto/dkg/feldman}/User.java | 10 ++++---- .../meerkat/crypto/dkg/gjkr}/MailHandler.java | 6 ++--- .../java/meerkat/crypto/dkg/gjkr}/Party.java | 6 ++--- .../meerkat/crypto/dkg/gjkr}/Protocol.java | 8 +++---- .../java/meerkat/crypto/dkg/gjkr}/User.java | 20 ++++++++-------- .../feldman}/VerifiableSecretSharing.java | 6 ++--- .../shamir/LagrangePolynomial.java | 4 ++-- .../secretsharing}/shamir/Polynomial.java | 6 ++--- .../secretsharing}/shamir/SecretSharing.java | 6 ++--- .../meerkat/crypto/utils}/Arithmetic.java | 2 +- .../java/meerkat/crypto/utils}/Channel.java | 2 +- .../meerkat/crypto/utils}/concrete/Fp.java | 4 ++-- .../src/main/proto/meerkat/DKGMessages.proto | 6 ++--- .../crypto/dkg/feldman}/DKGMaliciousUser.java | 6 ++--- .../meerkat/crypto/dkg/feldman}/DKGTest.java | 23 +++++++++---------- .../crypto/dkg/feldman}/DKGUserImplAbort.java | 4 ++-- .../dkg/gjkr}/SDKGMaliciousUserImpl.java | 6 ++--- .../meerkat/crypto/dkg/gjkr}/SDKGTest.java | 23 +++++++++---------- .../crypto/dkg/gjkr}/SDKGUserImplAbort.java | 4 ++-- .../feldman}/VerifiableSecretSharingTest.java | 4 ++-- .../shamir/PolynomialTests/AddTest.java | 8 +++---- .../PolynomialTests/InterpolationTest.java | 12 +++++----- .../PolynomialTests/MulByConstTest.java | 8 +++---- .../shamir/PolynomialTests/MulTest.java | 8 +++---- .../shamir/SecretSharingTest.java | 6 ++--- .../crypto/utils}/BigIntegerByteEncoder.java | 2 +- .../meerkat/crypto/utils}/ChannelImpl.java | 2 +- .../utils}/GenerateRandomPolynomial.java | 6 ++--- .../crypto/utils}/GenerateRandomPrime.java | 2 +- .../test/java/meerkat/crypto/utils}/Z.java | 2 +- .../Digest.java | 2 +- .../DigitalSignature.java | 2 +- .../Encryption.java | 2 +- .../concrete/ECDSADeterministicSignature.java | 2 +- .../concrete/ECDSASignature.java | 4 ++-- .../concrete/ECElGamalEncryption.java | 4 ++-- .../concrete/GlobalCryptoSetup.java | 4 ++-- .../concrete/SHA256Digest.java | 4 ++-- .../mixnet/Mix2ZeroKnowledgeProver.java | 2 +- .../mixnet/Mix2ZeroKnowledgeVerifier.java | 2 +- .../mixnet/Mixer.java | 2 +- .../mixnet/Trustee.java | 2 +- .../mixnet/Verifier.java | 2 +- .../ECDSADeterministicSignatureTest.java | 2 +- .../concrete/ECDSASignatureTest.java | 2 +- .../concrete/ECElGamalEncryptionTest.java | 2 +- .../concrete/ECElGamalUtils.java | 2 +- settings.gradle | 2 +- 59 files changed, 148 insertions(+), 150 deletions(-) rename {destributed-key-generation => distributed-key-generation}/build.gradle (100%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication => distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm}/MailHandler.java (93%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication => distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm}/MessageHandler.java (90%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman}/MailHandler.java (82%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman}/Party.java (84%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman}/Protocol.java (96%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman}/User.java (96%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr}/MailHandler.java (85%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr}/Party.java (68%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr}/Protocol.java (92%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr}/User.java (92%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable => distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/feldman}/VerifiableSecretSharing.java (93%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/main/java/meerkat/crypto/secretsharing}/shamir/LagrangePolynomial.java (94%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/main/java/meerkat/crypto/secretsharing}/shamir/Polynomial.java (95%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/main/java/meerkat/crypto/secretsharing}/shamir/SecretSharing.java (93%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/main/java/meerkat/crypto/utils}/Arithmetic.java (92%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/main/java/meerkat/crypto/utils}/Channel.java (95%) rename {destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/main/java/meerkat/crypto/utils}/concrete/Fp.java (88%) rename {meerkat-common => distributed-key-generation}/src/main/proto/meerkat/DKGMessages.proto (85%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman}/DKGMaliciousUser.java (89%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman}/DKGTest.java (85%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman}/DKGUserImplAbort.java (88%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr}/SDKGMaliciousUserImpl.java (87%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr}/SDKGTest.java (86%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol => distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr}/SDKGUserImplAbort.java (89%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/feldman}/VerifiableSecretSharingTest.java (93%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing}/shamir/PolynomialTests/AddTest.java (78%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing}/shamir/PolynomialTests/InterpolationTest.java (80%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing}/shamir/PolynomialTests/MulByConstTest.java (77%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing}/shamir/PolynomialTests/MulTest.java (78%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring => distributed-key-generation/src/test/java/meerkat/crypto/secretsharing}/shamir/SecretSharingTest.java (90%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/test/java/meerkat/crypto/utils}/BigIntegerByteEncoder.java (91%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/test/java/meerkat/crypto/utils}/ChannelImpl.java (98%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/test/java/meerkat/crypto/utils}/GenerateRandomPolynomial.java (82%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/test/java/meerkat/crypto/utils}/GenerateRandomPrime.java (94%) rename {destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis => distributed-key-generation/src/test/java/meerkat/crypto/utils}/Z.java (91%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/Digest.java (94%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/DigitalSignature.java (98%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/Encryption.java (96%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/concrete/ECDSADeterministicSignature.java (98%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/concrete/ECDSASignature.java (99%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/concrete/ECElGamalEncryption.java (98%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/concrete/GlobalCryptoSetup.java (92%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/concrete/SHA256Digest.java (95%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/mixnet/Mix2ZeroKnowledgeProver.java (93%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/mixnet/Mix2ZeroKnowledgeVerifier.java (92%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/mixnet/Mixer.java (79%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/mixnet/Trustee.java (56%) rename meerkat-common/src/main/java/meerkat/{destributed_key_generation => crypto}/mixnet/Verifier.java (56%) rename meerkat-common/src/test/java/meerkat/{destributed_key_generation => crypto}/concrete/ECDSADeterministicSignatureTest.java (96%) rename meerkat-common/src/test/java/meerkat/{destributed_key_generation => crypto}/concrete/ECDSASignatureTest.java (99%) rename meerkat-common/src/test/java/meerkat/{destributed_key_generation => crypto}/concrete/ECElGamalEncryptionTest.java (98%) rename meerkat-common/src/test/java/meerkat/{destributed_key_generation => crypto}/concrete/ECElGamalUtils.java (98%) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java index b519eb4..1d0d741 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BulletinClientWorker.java @@ -2,8 +2,8 @@ package meerkat.bulletinboard; import com.google.protobuf.Message; import meerkat.comm.CommunicationException; -import meerkat.destributed_key_generation.Digest; -import meerkat.destributed_key_generation.concrete.SHA256Digest; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; import meerkat.rest.ProtobufMessageBodyReader; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index b12649e..9d3f24a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -2,8 +2,8 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; -import meerkat.destributed_key_generation.Digest; -import meerkat.destributed_key_generation.concrete.SHA256Digest; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting; import meerkat.protobuf.Voting.BulletinBoardClientParams; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index d3957cf..81513f8 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -6,8 +6,8 @@ import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback; import meerkat.bulletinboard.callbacks.PostMessageFutureCallback; import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback; import meerkat.comm.CommunicationException; -import meerkat.destributed_key_generation.Digest; -import meerkat.destributed_key_generation.concrete.SHA256Digest; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 2c0a8d7..8402e55 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -13,8 +13,8 @@ import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; -import meerkat.destributed_key_generation.Digest; -import meerkat.destributed_key_generation.concrete.SHA256Digest; +import meerkat.crypto.Digest; +import meerkat.crypto.concrete.SHA256Digest; import javax.sql.DataSource; diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index fa4c60b..1c5e3c5 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -18,7 +18,7 @@ import java.util.Random; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; -import meerkat.destributed_key_generation.concrete.ECDSASignature; +import meerkat.crypto.concrete.ECDSASignature; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.MessageFilter; diff --git a/destributed-key-generation/build.gradle b/distributed-key-generation/build.gradle similarity index 100% rename from destributed-key-generation/build.gradle rename to distributed-key-generation/build.gradle diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java similarity index 93% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java index cc3b08b..3c2052e 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication; +package meerkat.crypto.dkg.comm; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.crypto.utils.Channel; import meerkat.protobuf.DKGMessages; /** diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java similarity index 90% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java index 0fa7a46..c33e99a 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/communication/MessageHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication; +package meerkat.crypto.dkg.comm; import com.google.protobuf.Message; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java similarity index 82% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java index a2d82b2..d2ca352 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java @@ -1,15 +1,15 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler; +import meerkat.crypto.dkg.comm.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. * an extension of MailHandler matching joint feldman protocol */ -public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler { +public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { /** * constructor diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Party.java similarity index 84% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Party.java index 90ee829..1b2cbe8 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Party.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Party.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.secretsharing.shamir.Polynomial; import java.util.ArrayList; import java.util.Arrays; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java similarity index 96% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index e3cddbd..616015a 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -1,8 +1,8 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.utilitis.Channel; -import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.utils.Channel; +import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; +import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java similarity index 96% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index 84f5bb8..eee1b85 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.utilitis.Channel; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.utils.Channel; +import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; @@ -59,7 +59,7 @@ public class User implements Runnable{ /** * mail handler registered to channel as ReceiverCallback */ - protected meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler mailHandler; + protected meerkat.crypto.dkg.comm.MailHandler mailHandler; /** * channel object @@ -360,7 +360,7 @@ public class User implements Runnable{ /** * an implementation of MessageHandler */ - public class MessageHandler implements meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler{ + public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler{ /** * commitment message is valid if: diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java similarity index 85% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java index 5f3ee3b..f82f057 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java @@ -1,15 +1,15 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler; +import meerkat.crypto.dkg.comm.MessageHandler; import meerkat.protobuf.DKGMessages; /** * Created by Tzlil on 2/29/2016. * an extension of MailHandler matching gjkr protocl */ -public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler { +public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { /** * flag that indicants whether the diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Party.java similarity index 68% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Party.java index d950beb..529b7be 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Party.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Party.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.secretsharing.shamir.Polynomial; import java.util.ArrayList; import java.util.HashSet; @@ -13,7 +13,7 @@ import java.util.Set; * contains all relevant information on specific party during * the run of the safe protocol */ -public class Party extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Party { +public class Party extends meerkat.crypto.dkg.feldman.Party { public Polynomial.Point shareT; public boolean ysDoneFlag; public ArrayList verifiableValues; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java similarity index 92% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java index a0512d6..a98265e 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; +import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; import meerkat.protobuf.DKGMessages; import org.factcenter.qilin.primitives.Group; @@ -17,7 +17,7 @@ import java.util.Set; * TODO: comments * TODO: put Channel (ChannelImpl) in constructor */ -public class Protocol extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol { +public class Protocol extends meerkat.crypto.dkg.feldman.Protocol { private VerifiableSecretSharing maskingShares; private final T h; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java similarity index 92% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java rename to distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java index 86ed127..cb4c693 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java @@ -1,10 +1,10 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.utilitis.Arithmetic; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; -import meerkat.destributed_key_generation.utilitis.Channel; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; +import meerkat.crypto.utils.Arithmetic; +import meerkat.crypto.utils.concrete.Fp; +import meerkat.crypto.utils.Channel; +import meerkat.crypto.secretsharing.shamir.Polynomial; +import meerkat.crypto.secretsharing.shamir.SecretSharing; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; @@ -22,7 +22,7 @@ import java.util.ArrayList; * 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 extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User { +public class User extends meerkat.crypto.dkg.feldman.User { /** * All parties participating in key generation. @@ -190,7 +190,7 @@ public class User extends meerkat.destributed_key_generation.concrete.distrib super.stage4(); } - private class MessageHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler { + private class MessageHandler extends meerkat.crypto.dkg.feldman.User.MessageHandler { boolean isStage4; /** @@ -259,10 +259,10 @@ public class User extends meerkat.destributed_key_generation.concrete.distrib synchronized (parties[i - 1]) { if (!isStage4) { if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified; + parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.NonDisqualified; } else { - parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.Disqualified; + parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.Disqualified; } if (j == id) { parties[i - 1].share = secret; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharing.java similarity index 93% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java rename to distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharing.java index 1544564..0c91431 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharing.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharing.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable; +package meerkat.crypto.secretsharing.feldman; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; +import meerkat.crypto.secretsharing.shamir.Polynomial; +import meerkat.crypto.secretsharing.shamir.SecretSharing; import org.factcenter.qilin.primitives.Group; import java.util.ArrayList; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/LagrangePolynomial.java similarity index 94% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java rename to distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/LagrangePolynomial.java index 0da8f48..e12d65f 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/LagrangePolynomial.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/LagrangePolynomial.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir; +package meerkat.crypto.secretsharing.shamir; -import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.crypto.utils.Arithmetic; import java.math.BigInteger; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java similarity index 95% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java rename to distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java index e0e2361..58f38fb 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/Polynomial.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir; +package meerkat.crypto.secretsharing.shamir; -import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.crypto.utils.Arithmetic; import java.math.BigInteger; import java.util.Arrays; @@ -100,7 +100,7 @@ public class Polynomial implements Comparable { /** * @param other - * @return new meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial of degree max(this degree,other degree) s.t for all x + * @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){ diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/SecretSharing.java similarity index 93% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java rename to distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/SecretSharing.java index d5e73aa..fb86993 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharing.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/SecretSharing.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir; +package meerkat.crypto.secretsharing.shamir; -import meerkat.destributed_key_generation.utilitis.Arithmetic; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.crypto.utils.Arithmetic; +import meerkat.crypto.utils.concrete.Fp; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Arithmetic.java similarity index 92% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java rename to distributed-key-generation/src/main/java/meerkat/crypto/utils/Arithmetic.java index 2aab0cf..6221a5c 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Arithmetic.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Arithmetic.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; /** * Created by Tzlil on 3/17/2016. diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java similarity index 95% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java rename to distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java index 294ffaf..6f477fe 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/Channel.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; diff --git a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java b/distributed-key-generation/src/main/java/meerkat/crypto/utils/concrete/Fp.java similarity index 88% rename from destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java rename to distributed-key-generation/src/main/java/meerkat/crypto/utils/concrete/Fp.java index d7d03bc..52fb324 100644 --- a/destributed-key-generation/src/main/java/meerkat/destributed_key_generation/utilitis/concrete/Fp.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/utils/concrete/Fp.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.utilitis.concrete; +package meerkat.crypto.utils.concrete; -import meerkat.destributed_key_generation.utilitis.Arithmetic; +import meerkat.crypto.utils.Arithmetic; import org.factcenter.qilin.primitives.concrete.Zpstar; import java.math.BigInteger; diff --git a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto b/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto similarity index 85% rename from meerkat-common/src/main/proto/meerkat/DKGMessages.proto rename to distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto index 046f586..0e40e17 100644 --- a/meerkat-common/src/main/proto/meerkat/DKGMessages.proto +++ b/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto @@ -4,7 +4,7 @@ package meerkat; option java_package = "meerkat.protobuf"; -message Mail{ +message Mail { enum Type { SHARE = 0; COMMITMENT = 1; @@ -29,14 +29,14 @@ message ShareMessage { bytes share = 3; } -message DoubleShareMessage{ +message DoubleShareMessage { int32 i = 1; int32 j = 2; bytes share = 3; bytes shareT = 4; } -message CommitmentMessage{ +message CommitmentMessage { int32 k = 1; bytes commitment = 2; } diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java similarity index 89% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java index 672de21..ebd2ff6 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGMaliciousUser.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.crypto.utils.Channel; import java.math.BigInteger; import java.util.*; @@ -44,7 +44,7 @@ public class DKGMaliciousUser extends User { @Override public void stage1() { dkg.broadcastCommitments(); - sendSecrets(); //insteadof dkg.sendSecrets(channel); + sendSecrets(); //insteadof crypto.sendSecrets(channel); } @Override diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java similarity index 85% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java index cac11df..18b3674 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java @@ -1,18 +1,17 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.utilitis.ChannelImpl; -import meerkat.destributed_key_generation.utilitis.Arithmetic; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; -import meerkat.destributed_key_generation.utilitis.Channel; -import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; -import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; +import meerkat.crypto.utils.ChannelImpl; +import meerkat.crypto.utils.Arithmetic; +import meerkat.crypto.utils.concrete.Fp; +import meerkat.crypto.utils.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.Before; import org.junit.Test; import java.math.BigInteger; @@ -122,7 +121,7 @@ public class DKGTest { id = ids.remove(random.nextInt(ids.size())); channel = new ChannelImpl(id,n); s = randomIntModQ(random); - dkg = new meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol(t, n, s, random, q, g, group, id,byteEncoder); + dkg = new meerkat.crypto.dkg.feldman.Protocol(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)){ diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java similarity index 88% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java index dc0f419..c2b05cb 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/joint_feldman_protocol/DKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol; +package meerkat.crypto.dkg.feldman; -import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.crypto.utils.Channel; import meerkat.protobuf.DKGMessages; /** diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java similarity index 87% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java index 7afb60e..f72b00a 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGMaliciousUserImpl.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.crypto.utils.Channel; import java.math.BigInteger; import java.util.Random; @@ -33,7 +33,7 @@ public class SDKGMaliciousUserImpl extends User { @Override public void stage1() { sdkg.computeAndBroadcastVerificationValues(); - sendSecrets(); //insteadof dkg.sendSecrets(channel); + sendSecrets(); //insteadof crypto.sendSecrets(channel); } @Override diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java similarity index 86% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java index d296810..b5c4c9f 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java @@ -1,19 +1,18 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.utilitis.ChannelImpl; -import meerkat.destributed_key_generation.utilitis.Arithmetic; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; -import meerkat.destributed_key_generation.utilitis.Channel; -import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing; -import meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing; -import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; +import meerkat.crypto.utils.ChannelImpl; +import meerkat.crypto.utils.Arithmetic; +import meerkat.crypto.utils.concrete.Fp; +import meerkat.crypto.utils.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.Before; import org.junit.Test; import java.math.BigInteger; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java similarity index 89% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java rename to distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java index e91d87e..9fc7756 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/distributed_key_generation/gjkr_secure_protocol/SDKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol; +package meerkat.crypto.dkg.gjkr; -import meerkat.destributed_key_generation.utilitis.Channel; +import meerkat.crypto.utils.Channel; import meerkat.protobuf.DKGMessages; /** diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharingTest.java similarity index 93% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharingTest.java index 1f2d15e..7992dfb 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/feldman_verifiable/VerifiableSecretSharingTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/feldman/VerifiableSecretSharingTest.java @@ -1,6 +1,6 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable; +package meerkat.crypto.secretsharing.feldman; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.secretsharing.shamir.Polynomial; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.junit.Before; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/AddTest.java similarity index 78% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/AddTest.java index 24c5e9f..79a9aef 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/AddTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/AddTest.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; -import meerkat.destributed_key_generation.utilitis.Z; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +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; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/InterpolationTest.java similarity index 80% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/InterpolationTest.java index 9462cec..ea857f8 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/InterpolationTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/InterpolationTest.java @@ -1,10 +1,10 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.crypto.secretsharing.shamir.PolynomialTests; -import meerkat.destributed_key_generation.utilitis.Arithmetic; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; +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; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulByConstTest.java similarity index 77% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulByConstTest.java index f63fc2b..77afc32 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulByConstTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulByConstTest.java @@ -1,8 +1,8 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.crypto.secretsharing.shamir.PolynomialTests; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; -import meerkat.destributed_key_generation.utilitis.Z; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.utils.GenerateRandomPolynomial; +import meerkat.crypto.utils.Z; +import meerkat.crypto.secretsharing.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulTest.java similarity index 78% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulTest.java index e9caa66..1f54247 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/PolynomialTests/MulTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/PolynomialTests/MulTest.java @@ -1,8 +1,8 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests; +package meerkat.crypto.secretsharing.shamir.PolynomialTests; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial; -import meerkat.destributed_key_generation.utilitis.Z; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; +import meerkat.crypto.utils.GenerateRandomPolynomial; +import meerkat.crypto.utils.Z; +import meerkat.crypto.secretsharing.shamir.Polynomial; import org.junit.Before; import org.junit.Test; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/SecretSharingTest.java similarity index 90% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java rename to distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/SecretSharingTest.java index cf1b8d3..021b529 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/concrete/secret_shring/shamir/SecretSharingTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/secretsharing/shamir/SecretSharingTest.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.concrete.secret_shring.shamir; +package meerkat.crypto.secretsharing.shamir; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; -import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime; +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; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/BigIntegerByteEncoder.java similarity index 91% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java rename to distributed-key-generation/src/test/java/meerkat/crypto/utils/BigIntegerByteEncoder.java index 4548451..2781abb 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/BigIntegerByteEncoder.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/BigIntegerByteEncoder.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; import java.math.BigInteger; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java similarity index 98% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java rename to distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java index f6e09f1..55b34fa 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/ChannelImpl.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; import com.google.protobuf.Message; import meerkat.protobuf.DKGMessages; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPolynomial.java similarity index 82% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java rename to distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPolynomial.java index 4648598..802c479 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPolynomial.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPolynomial.java @@ -1,7 +1,7 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; -import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial; -import meerkat.destributed_key_generation.utilitis.concrete.Fp; +import meerkat.crypto.secretsharing.shamir.Polynomial; +import meerkat.crypto.utils.concrete.Fp; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPrime.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPrime.java similarity index 94% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPrime.java rename to distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPrime.java index a0bee5a..b2969bf 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/GenerateRandomPrime.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/GenerateRandomPrime.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; import java.math.BigInteger; import java.util.Random; diff --git a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/Z.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/Z.java similarity index 91% rename from destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/Z.java rename to distributed-key-generation/src/test/java/meerkat/crypto/utils/Z.java index fecd227..1814f7e 100644 --- a/destributed-key-generation/src/test/java/meerkat/destributed_key_generation/utilitis/Z.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/Z.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.utilitis; +package meerkat.crypto.utils; import java.math.BigInteger; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java similarity index 94% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/Digest.java rename to meerkat-common/src/main/java/meerkat/crypto/Digest.java index 97b141e..06b012c 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation; +package meerkat.crypto; import com.google.protobuf.Message; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/DigitalSignature.java b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java similarity index 98% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/DigitalSignature.java rename to meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java index 0dd76d0..e7b64e5 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/DigitalSignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/DigitalSignature.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation; +package meerkat.crypto; import com.google.protobuf.ByteString; import com.google.protobuf.Message; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/Encryption.java b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java similarity index 96% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/Encryption.java rename to meerkat-common/src/main/java/meerkat/crypto/Encryption.java index 69b22b5..6a40d0d 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/Encryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation; +package meerkat.crypto; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java similarity index 98% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignature.java rename to meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java index 3e8b36f..0afbdd7 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSADeterministicSignature.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java similarity index 99% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSASignature.java rename to meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 5578421..887b8e8 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import java.io.IOException; import java.io.InputStream; @@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.DigitalSignature; +import meerkat.crypto.DigitalSignature; import meerkat.protobuf.Crypto.Signature; import javax.security.auth.callback.Callback; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java similarity index 98% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java rename to meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 973b3c7..6258f5f 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -1,9 +1,9 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.Encryption; +import meerkat.crypto.Encryption; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java similarity index 92% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java rename to meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java index 7efc793..4f2e7a5 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/GlobalCryptoSetup.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.slf4j.Logger; @@ -8,7 +8,7 @@ import java.security.Provider; import java.security.Security; /** - * A class that performs required destributed_key_generation setup + * A class that performs required crypto setup */ public class GlobalCryptoSetup { final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java similarity index 95% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java rename to meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index 6c2fce2..4f60af3 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -1,8 +1,8 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; -import meerkat.destributed_key_generation.Digest; +import meerkat.crypto.Digest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java similarity index 93% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java rename to meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index aa63aeb..1113bfd 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.mixnet; +package meerkat.crypto.mixnet; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java similarity index 92% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java rename to meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java index 6faf0ca..dd3c251 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mix2ZeroKnowledgeVerifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.mixnet; +package meerkat.crypto.mixnet; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java similarity index 79% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java rename to meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java index 2b6d3e8..52e8844 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Mixer.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mixer.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.mixnet; +package meerkat.crypto.mixnet; import java.util.List; import static meerkat.protobuf.Voting.*; diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java similarity index 56% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java rename to meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java index ded66c5..e8044cd 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Trustee.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Trustee.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.mixnet; +package meerkat.crypto.mixnet; /** * Created by talm on 25/10/15. diff --git a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java similarity index 56% rename from meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java rename to meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java index 18271ed..b733317 100644 --- a/meerkat-common/src/main/java/meerkat/destributed_key_generation/mixnet/Verifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Verifier.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.mixnet; +package meerkat.crypto.mixnet; /** * Created by talm on 25/10/15. diff --git a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java similarity index 96% rename from meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java rename to meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java index 86ae311..4baa741 100644 --- a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSADeterministicSignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSADeterministicSignatureTest.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; diff --git a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java similarity index 99% rename from meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java rename to meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java index 9e90cce..e5b448d 100644 --- a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECDSASignatureTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECDSASignatureTest.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; diff --git a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java similarity index 98% rename from meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java rename to meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java index b09fbce..81375e0 100644 --- a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalEncryptionTest.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalEncryptionTest.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.Crypto; diff --git a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java similarity index 98% rename from meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java rename to meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java index 9b5de78..66e1647 100644 --- a/meerkat-common/src/test/java/meerkat/destributed_key_generation/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java @@ -1,4 +1,4 @@ -package meerkat.destributed_key_generation.concrete; +package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.GeneratedMessage; diff --git a/settings.gradle b/settings.gradle index f019032..236a0d1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,5 +4,5 @@ include 'bulletin-board-server' include 'polling-station' include 'restful-api-common' include 'bulletin-board-client' -include 'destributed-key-generation' +include 'distributed-key-generation' From 78207532ecc3c129eedd9e18597d673114a997a0 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Mon, 11 Apr 2016 20:51:40 +0300 Subject: [PATCH 045/106] protobuf naming convention --- .../src/main/proto/meerkat/DKGMessages.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto b/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto index 0e40e17..c7d9cba 100644 --- a/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto +++ b/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto @@ -18,7 +18,7 @@ message Mail { } int32 sender = 1; int32 destination = 2; - bool isPrivate = 3; + bool is_private = 3; Type type = 4; bytes message = 5; } @@ -33,7 +33,7 @@ message DoubleShareMessage { int32 i = 1; int32 j = 2; bytes share = 3; - bytes shareT = 4; + bytes share_t = 4; } message CommitmentMessage { From c798e827dcfaa0f1f7ada51d501dfc9d0dbe9656 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Tue, 12 Apr 2016 02:21:46 +0300 Subject: [PATCH 046/106] More renaming and refactoring of DKG code --- .../meerkat/crypto/dkg/comm/MailHandler.java | 56 +--- .../crypto/dkg/comm/MessageHandler.java | 63 ++-- .../meerkat/crypto/dkg/comm/MessageUtils.java | 36 +++ .../crypto/dkg/feldman/MailHandler.java | 34 +- .../meerkat/crypto/dkg/feldman/Protocol.java | 25 +- .../java/meerkat/crypto/dkg/feldman/User.java | 214 +++++++------ .../meerkat/crypto/dkg/gjkr/MailHandler.java | 37 +-- .../meerkat/crypto/dkg/gjkr/Protocol.java | 27 +- .../java/meerkat/crypto/dkg/gjkr/User.java | 302 +++++++++--------- .../java/meerkat/crypto/utils/Channel.java | 16 +- .../meerkat/{DKGMessages.proto => DKG.proto} | 40 +-- .../crypto/dkg/feldman/DKGUserImplAbort.java | 6 +- .../crypto/dkg/gjkr/SDKGUserImplAbort.java | 5 +- .../meerkat/crypto/utils/ChannelImpl.java | 28 +- 14 files changed, 429 insertions(+), 460 deletions(-) create mode 100644 distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageUtils.java rename distributed-key-generation/src/main/proto/meerkat/{DKGMessages.proto => DKG.proto} (63%) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java index 3c2052e..5cd1be0 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java @@ -1,8 +1,11 @@ package meerkat.crypto.dkg.comm; +import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import meerkat.crypto.utils.Channel; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by Tzlil on 2/14/2016. @@ -10,6 +13,7 @@ import meerkat.protobuf.DKGMessages; * an implementation of ReceiverCallback */ public abstract class MailHandler implements Channel.ReceiverCallback{ + final Logger logger = LoggerFactory.getLogger(getClass()); /** * fixed value for broadcasting @@ -30,50 +34,20 @@ public abstract class MailHandler implements Channel.ReceiverCallback{ } /** - * extract message from mail - * @param mail - * @return + * Was this broadcastMessage was received by broadcast channel + * @param broadcastMessage + * @return broadcastMessage user destination == BROADCAST */ - public abstract Message extractMessage(DKGMessages.Mail mail); - - /** - * is this mail was received by broadcast channel - * @param mail - * @return mail user destination == BROADCAST - */ - public boolean isBroadcast(DKGMessages.Mail mail){ - return mail.getDestination() == BROADCAST; + public boolean isBroadcast(DKG.BroadcastMessage broadcastMessage){ + return broadcastMessage.getDestination() == BROADCAST; } @Override - public void receiveMail(DKGMessages.Mail mail){ - Message message = extractMessage(mail); - if (message == null) - return; - - switch (mail.getType()) { - case SHARE: - messageHandler.handleShareMessage(mail.getSender(), isBroadcast(mail),message); - break; - case COMMITMENT: - messageHandler.handleCommitmentMessage(mail.getSender(), isBroadcast(mail),message); - break; - case DONE: - messageHandler.handleDoneMessage(mail.getSender(), isBroadcast(mail),message); - break; - case COMPLAINT: - messageHandler.handleComplaintMessage(mail.getSender(), isBroadcast(mail),message); - break; - case ANSWER: - messageHandler.handleAnswerMessage(mail.getSender(), isBroadcast(mail),message); - break; - case ABORT: - messageHandler.handleAbortMessage(mail.getSender(), isBroadcast(mail),message); - break; - default: - break; + public void receiveMail(DKG.BroadcastMessage envelope) { + try { + messageHandler.handleMessage(envelope); + } catch (InvalidProtocolBufferException e) { + logger.warn("Received invalid protocol buffer from channel", e); } - - } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java index c33e99a..4927e94 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java @@ -1,39 +1,50 @@ package meerkat.crypto.dkg.comm; +import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; +import meerkat.protobuf.DKG; /** * Created by Tzlil on 2/14/2016. * an interface for handling received messages */ public interface MessageHandler { - /** - * handle share message - */ - void handleShareMessage(int sender, boolean isBroadcast, Message message); /** - * handle commitment message + * 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 */ - void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); - - /** - * handle complaint message - */ - void handleComplaintMessage(int sender, boolean isBroadcast, Message message); - - /** - * handle done message - */ - void handleDoneMessage(int sender, boolean isBroadcast, Message message); - - /** - * handle answer message - */ - void handleAnswerMessage(int sender, boolean isBroadcast, Message message); - - /** - * handle abort message - */ - void handleAbortMessage(int sender, boolean isBroadcast, Message message); + void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException; +// +// /** +// * handle share message +// */ +// void handleShareMessage(int sender, boolean isBroadcast, Message message); +// +// /** +// * handle commitment message +// */ +// void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); +// +// /** +// * handle complaint message +// */ +// void handleComplaintMessage(int sender, boolean isBroadcast, Message message); +// +// /** +// * handle done message +// */ +// void handleDoneMessage(int sender, boolean isBroadcast, Message message); +// +// /** +// * handle answer message +// */ +// void handleAnswerMessage(int sender, boolean isBroadcast, Message message); +// +// /** +// * handle abort message +// */ +// void handleAbortMessage(int sender, boolean isBroadcast, Message message); } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageUtils.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageUtils.java new file mode 100644 index 0000000..a0cb79a --- /dev/null +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageUtils.java @@ -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(); + } +} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java index d2ca352..dabfa17 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java @@ -3,7 +3,7 @@ package meerkat.crypto.dkg.feldman; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; /** * Created by Tzlil on 2/29/2016. @@ -18,36 +18,4 @@ public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { public MailHandler(MessageHandler messageHandler) { super(messageHandler); } - - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SHARE: - message = DKGMessages.ShareMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.ShareMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index 616015a..74d35d4 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -4,13 +4,15 @@ import meerkat.crypto.utils.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; -import meerkat.protobuf.DKGMessages; +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. * @@ -126,13 +128,13 @@ public class Protocol extends VerifiableSecretSharing { * @param commitments */ public void broadcastCommitments(ArrayList commitments){ - DKGMessages.CommitmentMessage commitmentMessage; + DKG.CommitmentMessage commitmentMessage; for (int k = 0; k <= t ; k++){ - commitmentMessage = DKGMessages.CommitmentMessage.newBuilder() + commitmentMessage = DKG.CommitmentMessage.newBuilder() .setCommitment(ByteString.copyFrom(encoder.encode(commitments.get(k)))) .setK(k) .build(); - channel.broadcastMessage(DKGMessages.Mail.Type.COMMITMENT, commitmentMessage); + channel.broadcastMessage(createMessage(DKG.Payload.Type.COMMITMENT, commitmentMessage)); } } @@ -142,12 +144,12 @@ public class Protocol extends VerifiableSecretSharing { */ public void sendSecret(int j){ ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray()); - channel.sendMessage(j, DKGMessages.Mail.Type.SHARE, - DKGMessages.ShareMessage.newBuilder() + channel.sendMessage(j, createMessage(DKG.Payload.Type.SHARE, + DKG.ShareMessage.newBuilder() .setI(id) .setJ(j) .setShare(secret) - .build()); + )); } /** @@ -207,10 +209,10 @@ public class Protocol extends VerifiableSecretSharing { */ private void broadcastComplaint(int i){ //message = new Message(Type.Complaint, j) - DKGMessages.IDMessage complaint = DKGMessages.IDMessage.newBuilder() + DKG.IDMessage complaint = DKG.IDMessage.newBuilder() .setId(i) .build(); - channel.broadcastMessage(DKGMessages.Mail.Type.COMPLAINT, complaint); + channel.broadcastMessage(createMessage(DKG.Payload.Type.COMPLAINT, complaint)); } /** @@ -218,11 +220,10 @@ public class Protocol extends VerifiableSecretSharing { * @param j */ public void broadcastComplaintAnswer(int j){ - channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER, DKGMessages.ShareMessage.newBuilder() + channel.broadcastMessage(createMessage(DKG.Payload.Type.ANSWER, DKG.ShareMessage.newBuilder() .setI(id) .setJ(j) - .setShare(ByteString.copyFrom(getShare(j).y.toByteArray())) - .build()); + .setShare(ByteString.copyFrom(getShare(j).y.toByteArray())))); } /** diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index eee1b85..4e4f155 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -1,16 +1,19 @@ package meerkat.crypto.dkg.feldman; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.utils.Channel; import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; import org.factcenter.qilin.primitives.Group; import java.math.BigInteger; import java.util.ArrayList; import java.util.Set; +import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; + /** * Created by Tzlil on 3/14/2016. * @@ -176,11 +179,10 @@ public class User implements Runnable{ * 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(){ + protected void stage2() { dkg.broadcastComplaints(); //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); + channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); } @@ -360,35 +362,19 @@ public class User implements Runnable{ /** * an implementation of MessageHandler */ - public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler{ + public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler { /** * 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, DKGMessages.CommitmentMessage commitmentMessage){ + 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; } - /** - * saves the commitment - */ - @Override - public void handleCommitmentMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.CommitmentMessage commitmentMessage = (DKGMessages.CommitmentMessage) message; - if(isValidCommitmentMessage(sender,isBroadcast,commitmentMessage)){ - int i = sender - 1; - int k = commitmentMessage.getK(); - synchronized (parties[i]) { - parties[i].commitments.set(k, extractCommitment(commitmentMessage)); - parties[i].notify(); - } - } - } - /** * secret message is valid if: * 1. it was received in private chanel @@ -396,7 +382,7 @@ public class User implements Runnable{ * 3. secret.i == i * 4. secret.j == id */ - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.ShareMessage secretMessage){ + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ int i = secretMessage.getI(); int j = secretMessage.getJ(); if(sender != i || isBroadcast) @@ -406,22 +392,6 @@ public class User implements Runnable{ } - /** - * saves the secret - */ - @Override - public void handleShareMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; - if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - Polynomial.Point secret = extractShare(id,secretMessage.getShare()); - synchronized (parties[i -1]) { - parties[i - 1].share = secret; - parties[i - 1].notify(); - } - } - } - /** * done message is valid if: * 1. it was received in broadcast chanel @@ -431,46 +401,18 @@ public class User implements Runnable{ return isBroadcast && !parties[sender - 1].doneFlag; } - /** - * marks that the sender was finished sending all his complaints - */ - @Override - public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { - if(isValidDoneMessage(sender,isBroadcast)) { - synchronized (parties[sender - 1]) { - parties[sender - 1].doneFlag = true; - parties[sender - 1].notify(); - } - } - } /** * 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, DKGMessages.IDMessage complaintMessage){ + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){ int i = sender; int j = complaintMessage.getId(); return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK); } - /** - * marks that the sender was complained against id - */ - @Override - public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.IDMessage complaintMessage = (DKGMessages.IDMessage)message; - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - synchronized (parties[j - 1]) { - parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; - parties[j - 1].notify(); - } - } - } - /** * answer message is valid if: * 1. it was received in broadcast chanel @@ -478,7 +420,7 @@ public class User implements Runnable{ * 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, DKGMessages.ShareMessage secretMessage){ + protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ int i = secretMessage.getI(); int j = secretMessage.getJ(); if(sender != i || !isBroadcast) @@ -487,40 +429,108 @@ public class User implements Runnable{ return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(Protocol.ComplaintState.Waiting); } - /** - * 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 - */ - @Override - public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message; - if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - Polynomial.Point secret = extractShare(j,secretMessage.getShare()); - synchronized (parties[i - 1]) { - 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; - } - parties[i - 1].notify(); - } - } - } - /** - * marks that the sender was aborted - */ @Override - public void handleAbortMessage(int sender, boolean isBroadcast, Message message) { - synchronized (parties[sender - 1]) { - parties[sender - 1].aborted = true; - parties[sender - 1].notify(); + public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException { + int sender = envelope.getSender(); + boolean isBroadcast = !envelope.getIsPrivate(); + DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); + + switch (msg.getType()) { + case COMMITMENT: + /** + * saves the commitment + */ + DKG.CommitmentMessage commitmentMessage = msg.getCommitment(); + if (isValidCommitmentMessage(sender, isBroadcast, commitmentMessage)) { + int i = sender - 1; + int k = commitmentMessage.getK(); + synchronized (parties[i]) { + parties[i].commitments.set(k, extractCommitment(commitmentMessage)); + parties[i].notify(); + } + } + break; + + + case SHARE: + /** + * saves the secret + */ + DKG.ShareMessage secretMessage = msg.getShare(); + if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + Polynomial.Point secret = extractShare(id,secretMessage.getShare()); + synchronized (parties[i -1]) { + parties[i - 1].share = secret; + parties[i - 1].notify(); + } + } + break; + + case DONE: + + /** + * marks that the sender was finished sending all his complaints + */ + if(isValidDoneMessage(sender,isBroadcast)) { + synchronized (parties[sender - 1]) { + parties[sender - 1].doneFlag = true; + parties[sender - 1].notify(); + } + } + break; + + case COMPLAINT: + /** + * marks that the sender was complained against id + */ + DKG.IDMessage complaintMessage = msg.getId(); + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + synchronized (parties[j - 1]) { + parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; + parties[j - 1].notify(); + } + } + 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 + */ + secretMessage = msg.getShare(); + if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + Polynomial.Point secret = extractShare(j,secretMessage.getShare()); + synchronized (parties[i - 1]) { + 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; + } + parties[i - 1].notify(); + } + } + break; + case ABORT: + /** + * marks that the sender was aborted + */ + synchronized (parties[sender - 1]) { + parties[sender - 1].aborted = true; + parties[sender - 1].notify(); + } + break; + + + } } @@ -541,7 +551,7 @@ public class User implements Runnable{ * @param commitmentMessage * @return */ - public T extractCommitment(DKGMessages.CommitmentMessage commitmentMessage){ + public T extractCommitment(DKG.CommitmentMessage commitmentMessage){ return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray()); } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java index f82f057..36f970e 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java @@ -3,7 +3,7 @@ package meerkat.crypto.dkg.gjkr; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; /** * Created by Tzlil on 2/29/2016. @@ -26,41 +26,6 @@ public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { this.isStage4 = false; } - @Override - public Message extractMessage(DKGMessages.Mail mail) { - try { - Message message; - switch (mail.getType()) { - case SHARE: - message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); - break; - case COMMITMENT: - message = DKGMessages.CommitmentMessage.parseFrom(mail.getMessage()); - break; - case COMPLAINT: - if(!isStage4) - message = DKGMessages.IDMessage.parseFrom(mail.getMessage()); - else - message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); - break; - case DONE: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - case ANSWER: - message = DKGMessages.DoubleShareMessage.parseFrom(mail.getMessage()); - break; - case ABORT: - message = DKGMessages.EmptyMessage.parseFrom(mail.getMessage()); - break; - default: - return null; - } - return message; - } catch (InvalidProtocolBufferException e) { - return null; - } - } - /** * setter * @param stage4 diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java index a98265e..aad773c 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/Protocol.java @@ -1,9 +1,10 @@ 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.DKGMessages; +import meerkat.protobuf.DKG; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.util.ByteEncoder; @@ -52,9 +53,9 @@ public class Protocol extends meerkat.crypto.dkg.feldman.Protocol { public void sendSecret(int j) { Polynomial.Point secret = getShare(j); Polynomial.Point secretT = maskingShares.getShare(j); - DKGMessages.DoubleShareMessage doubleSecretMessage = doubleShareMessage(id,j,secret,secretT); + DKG.ShareMessage doubleSecretMessage = createShareMessage(id,j,secret,secretT); // TODO: Change SHARE to SHARE - channel.sendMessage(j, DKGMessages.Mail.Type.SHARE, doubleSecretMessage); + channel.sendMessage(j, MessageUtils.createMessage(DKG.Payload.Type.SHARE, doubleSecretMessage)); } @@ -90,8 +91,8 @@ public class Protocol extends meerkat.crypto.dkg.feldman.Protocol { * @param i */ private void broadcastComplaint(Polynomial.Point share, Polynomial.Point shareT, int i){ - DKGMessages.DoubleShareMessage complaint = doubleShareMessage(i,id,share,shareT); - channel.broadcastMessage(DKGMessages.Mail.Type.COMPLAINT,complaint); + DKG.ShareMessage complaint = createShareMessage(i,id,share,shareT); + channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.COMPLAINT, complaint)); } /** @@ -124,7 +125,7 @@ public class Protocol extends meerkat.crypto.dkg.feldman.Protocol { } /** - * pack share, shareT i,j to doubleShareMessage + * pack share, shareT i,j to createShareMessage * @param i * @param j * @param share @@ -132,26 +133,26 @@ public class Protocol extends meerkat.crypto.dkg.feldman.Protocol { * @return */ - private DKGMessages.DoubleShareMessage doubleShareMessage(int i, int j, Polynomial.Point share, Polynomial.Point shareT){ - DKGMessages.DoubleShareMessage doubleShareMessage = DKGMessages.DoubleShareMessage.newBuilder() + 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 doubleShareMessage; + return ShareMessage; } @Override public void broadcastComplaintAnswer(int j) { - DKGMessages.DoubleShareMessage answer = doubleShareMessage(id,j,getShare(j) + DKG.ShareMessage answer = createShareMessage(id,j,getShare(j) , maskingShares.getShare(j)); - channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER,answer); + channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER, answer)); } public void broadcastAnswer(Polynomial.Point secret, Polynomial.Point secretT, int i){ - DKGMessages.DoubleShareMessage complaint = doubleShareMessage(i,id,secret,secretT); - channel.broadcastMessage(DKGMessages.Mail.Type.ANSWER,complaint); + DKG.ShareMessage complaint = createShareMessage(i,id,secret,secretT); + channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER,complaint)); } /** diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java index cb4c693..6a3e0a4 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java @@ -1,25 +1,28 @@ package meerkat.crypto.dkg.gjkr; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; import meerkat.crypto.utils.Channel; import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; +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. - * + *

* implementation of gjkr protocol user. - * - * this protocol extends joint feldman protocol by splitting the protocol to commitment stage (stages 1,2,3) - * and reviling stage (stage 4). - * - * as in joint feldman, each party in QUAL has his own share of the generated random key. + *

+ * this protocol extends joint Feldman protocol by splitting the protocol to commitment stage (stages 1,2,3) + * and revealing stage (stage 4). + *

+ * 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 extends meerkat.crypto.dkg.feldman.User { @@ -42,7 +45,8 @@ public class User extends meerkat.crypto.dkg.feldman.User { /** * constructor - * @param sdkg gjkr protocol object + * + * @param sdkg gjkr protocol object * @param channel channel object */ public User(Protocol sdkg, Channel channel) { @@ -52,15 +56,16 @@ public class User extends meerkat.crypto.dkg.feldman.User { } @Override - protected void registerReceiverCallback(){ + protected void registerReceiverCallback() { this.messageHandler = new MessageHandler(); this.mailHandler = new MailHandler(messageHandler); this.channel.registerReceiverCallback(mailHandler); } + /** * 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. + * 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() { @@ -69,11 +74,11 @@ public class User extends meerkat.crypto.dkg.feldman.User { } @Override - protected void waitUntilStageOneCompleted(){ + protected void waitUntilStageOneCompleted() { super.waitUntilStageOneCompleted(); // save the received commitments as verification values ArrayList temp; - for (int i = 0 ; i < n; i++){ + for (int i = 0; i < n; i++) { temp = parties[i].verifiableValues; parties[i].verifiableValues = parties[i].commitments; parties[i].commitments = temp; @@ -82,26 +87,25 @@ public class User extends meerkat.crypto.dkg.feldman.User { /** * 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 + * 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(){ + protected void stage2() { sdkg.broadcastComplaints(); //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); + channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); } /** * broadcast commitments and recover parties information if necessary */ - private void resolveQualifyingPublicKey(){ + private void resolveQualifyingPublicKey() { sdkg.broadcastCommitments(); // wait until all parties in QUAL broadcast their commitments or aborted - for (int i:QUAL) { - for(int k = 0; k <= t; k++) { + for (int i : QUAL) { + for (int k = 0; k <= t; k++) { synchronized (parties[i - 1]) { while (parties[i - 1].commitments.get(k) == null && !parties[i - 1].aborted) { try { @@ -115,11 +119,9 @@ public class User extends meerkat.crypto.dkg.feldman.User { } sdkg.computeAndBroadcastComplaints(QUAL); //broadcast done message after all complaints - DKGMessages.EmptyMessage doneMessage = DKGMessages.EmptyMessage.newBuilder().build(); - channel.broadcastMessage(DKGMessages.Mail.Type.DONE,doneMessage); - + channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); // wait until all parties in QUAL done or aborted - for (int i:QUAL) { + for (int i : QUAL) { synchronized ((parties[i - 1])) { while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { try { @@ -132,13 +134,13 @@ public class User extends meerkat.crypto.dkg.feldman.User { } // broadcast i private secret foreach i in QUAL that aborted - for (int i:QUAL) { - if(parties[i - 1].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 - for (int i:QUAL) { + for (int i : QUAL) { synchronized ((parties[i - 1])) { if (parties[i - 1].aborted) { while (parties[i - 1].recoverSharesSet.size() <= t) { @@ -153,33 +155,33 @@ public class User extends meerkat.crypto.dkg.feldman.User { } Arithmetic arithmetic = new Fp(sdkg.getQ()); // restore necessary information - for (int i = 0; i < n ; i++) { - if(parties[i].recoverSharesSet.isEmpty()){ + 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){ + for (Polynomial.Point share : parties[i].recoverSharesSet) { shares[j++] = share; - if (j >= shares.length){ + if (j >= shares.length) { break; } } - Polynomial polynomial = SecretSharing.recoverPolynomial(shares,arithmetic); + 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])); + 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); + parties[i].share = new Polynomial.Point(BigInteger.valueOf(id), polynomial); } } /** * notifies mail handler and message handler that stage 4 was started */ - protected void setStage4(){ + protected void setStage4() { this.messageHandler.isStage4 = true; - ((MailHandler)this.mailHandler).setStage4(true); + ((MailHandler) this.mailHandler).setStage4(true); } @Override @@ -193,158 +195,148 @@ public class User extends meerkat.crypto.dkg.feldman.User { private class MessageHandler extends meerkat.crypto.dkg.feldman.User.MessageHandler { boolean isStage4; - /** - * as in super, with extension to double secret message - */ - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKGMessages.DoubleShareMessage doubleSecretMessage) { - DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setShare(doubleSecretMessage.getShare()) - .build(); - return super.isValidSecretMessage(sender,isBroadcast,secretMessage); - } - - /** - * as in super, with extension to double secret message - */ - @Override - public void handleShareMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message; - 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(); - } - } - } /** * 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 + * 1. it was received in broadcast chanel + * 2. secret.j == sender + * 3. QUAL contains i and j */ - protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKGMessages.DoubleShareMessage doubleSecretMessage) { - if(!isStage4) { - DKGMessages.ShareMessage secretMessage = DKGMessages.ShareMessage.newBuilder() - .setI(doubleSecretMessage.getI()) - .setJ(doubleSecretMessage.getJ()) - .setShare(doubleSecretMessage.getShare()) - .build(); - return super.isValidAnswerMessage(sender, isBroadcast, secretMessage); - }else{ + 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 + return isBroadcast && j == sender && parties[i - 1].aborted && !parties[j - 1].aborted && QUAL.contains(i) && QUAL.contains(j); } } - /** - * if !isStage4 as super, with extension to double secret message - * else saves secret - */ - @Override - public void handleAnswerMessage(int sender, boolean isBroadcast, Message message) { - DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message; - 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(); - } - } - } /** * as in super with respect to protocol stage */ @Override protected boolean isValidDoneMessage(int sender, boolean isBroadcast) { - if(!isStage4) { + if (!isStage4) { return super.isValidDoneMessage(sender, isBroadcast); - }else{ - return isBroadcast && !parties[sender - 1].ysDoneFlag; - } - } - - /** - * as in super with respect to protocol state - */ - @Override - public void handleDoneMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) - super.handleDoneMessage(sender, isBroadcast, message); - else{ - if(isValidDoneMessage(sender,isBroadcast)) { - synchronized (parties[sender - 1]) { - parties[sender - 1].ysDoneFlag = true; - parties[sender - 1].notify(); - } - } + } 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 + * 1. it was received in broadcast chanel + * 2. secret.j == sender + * 3. QUAL contains i and j */ protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, - DKGMessages.DoubleShareMessage complaintMessage){ + DKG.ShareMessage complaintMessage) { int i = complaintMessage.getI(); int j = complaintMessage.getJ(); return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); } - /** - * 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 - */ + @Override - public void handleComplaintMessage(int sender, boolean isBroadcast, Message message) { - if(!isStage4) { - super.handleComplaintMessage(sender, isBroadcast, message); - }else { - DKGMessages.DoubleShareMessage ysComplaintMessage =(DKGMessages.DoubleShareMessage)message; - 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)) { + public void handleMessage(DKG.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].aborted = true; + 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 + */ + 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 { + 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; } } } -} +} \ No newline at end of file diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java index 6f477fe..97a6060 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java @@ -1,32 +1,36 @@ package meerkat.crypto.utils; import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; /** * 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 receiveMail(DKGMessages.Mail mail); + public void receiveMail(DKG.BroadcastMessage envelope); } /** * sends a private message * @param destUser destination user's identifier - * @param type message type * @param msg message */ - public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg); + public void sendMessage(int destUser, Message msg); /** * broadcasts a message to all parties (including the sender) - * @param type message type * @param msg message */ - public void broadcastMessage(DKGMessages.Mail.Type type, Message msg); + public void broadcastMessage(Message msg); /** * Register a callback to handle received messages. diff --git a/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto b/distributed-key-generation/src/main/proto/meerkat/DKG.proto similarity index 63% rename from distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto rename to distributed-key-generation/src/main/proto/meerkat/DKG.proto index c7d9cba..235f062 100644 --- a/distributed-key-generation/src/main/proto/meerkat/DKGMessages.proto +++ b/distributed-key-generation/src/main/proto/meerkat/DKG.proto @@ -4,7 +4,15 @@ package meerkat; option java_package = "meerkat.protobuf"; -message Mail { +message BroadcastMessage { + int32 sender = 1; + int32 destination = 2; + bool is_private = 3; + + bytes payload = 5; +} + +message Payload { enum Type { SHARE = 0; COMMITMENT = 1; @@ -16,23 +24,25 @@ message Mail { YANSWER = 7; ABORT = 8; } - int32 sender = 1; - int32 destination = 2; - bool is_private = 3; - Type type = 4; - bytes message = 5; + + Type type = 1; + + oneof specific { + 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; -} - -message DoubleShareMessage { - int32 i = 1; - int32 j = 2; - bytes share = 3; + // For double shares (used in GJKR protocol) bytes share_t = 4; } @@ -40,9 +50,3 @@ message CommitmentMessage { int32 k = 1; bytes commitment = 2; } - -message EmptyMessage{} - -message IDMessage{ - int32 id = 1; -} diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java index c2b05cb..902d103 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java @@ -1,7 +1,9 @@ package meerkat.crypto.dkg.feldman; import meerkat.crypto.utils.Channel; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; + +import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; /** * Created by Tzlil on 3/14/2016. @@ -18,7 +20,7 @@ public class DKGUserImplAbort extends User { private void sendAbort(){ - channel.broadcastMessage(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + channel.broadcastMessage(createMessage(DKG.Payload.Type.ABORT)); } @Override diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java index 9fc7756..b067c1a 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java @@ -1,7 +1,8 @@ package meerkat.crypto.dkg.gjkr; +import meerkat.crypto.dkg.comm.MessageUtils; import meerkat.crypto.utils.Channel; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; /** * Created by Tzlil on 3/14/2016. @@ -18,7 +19,7 @@ public class SDKGUserImplAbort extends User { private void abort(){ //stopReceiver(); - channel.broadcastMessage(DKGMessages.Mail.Type.ABORT,DKGMessages.EmptyMessage.getDefaultInstance()); + channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT)); } @Override diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java index 55b34fa..dfb1bfb 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java @@ -1,7 +1,7 @@ package meerkat.crypto.utils; import com.google.protobuf.Message; -import meerkat.protobuf.DKGMessages; +import meerkat.protobuf.DKG; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; @@ -16,7 +16,7 @@ public class ChannelImpl implements Channel { public static int BROADCAST = 0; private static ChannelImpl[] channels = null; - protected final Queue mailbox; + protected final Queue mailbox; protected final int id; protected final int n; protected Thread receiverThread; @@ -26,50 +26,50 @@ public class ChannelImpl implements Channel { if (channels == null){ channels = new ChannelImpl[n]; } - this.mailbox = new ArrayBlockingQueue( n * n * n); + this.mailbox = new ArrayBlockingQueue( n * n * n); this.id = id; this.n = n; channels[id - 1] = this; } - public int getId() { + @Override + public int getSourceId() { return id; } + @Override - public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg) { + public void sendMessage(int destUser, Message msg) { if(destUser < 1 || destUser > n) return; ChannelImpl channel = channels[destUser - 1]; if (channel == null) return; - DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() .setSender(id) .setDestination(destUser) .setIsPrivate(true) - .setType(type) - .setMessage(msg.toByteString()) + .setPayload(msg.toByteString()) .build(); synchronized (channel.mailbox) { - channel.mailbox.add(mail); + channel.mailbox.add(broadcastMessage); channel.mailbox.notify(); } } @Override - public void broadcastMessage(DKGMessages.Mail.Type type,Message msg) { + public void broadcastMessage(Message msg) { ChannelImpl channel; - DKGMessages.Mail mail = DKGMessages.Mail.newBuilder() + DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() .setSender(id) .setDestination(BROADCAST) .setIsPrivate(false) - .setType(type) - .setMessage(msg.toByteString()) + .setPayload(msg.toByteString()) .build(); for (int i = 0 ; i < n ; i++){ channel = channels[i]; synchronized (channel.mailbox) { - channel.mailbox.add(mail); + channel.mailbox.add(broadcastMessage); channel.mailbox.notify(); } } From c806e7b32a6ffba5f08cb7ff0fffe8bb78051a16 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Wed, 13 Apr 2016 09:46:24 +0300 Subject: [PATCH 047/106] Added Deletion to Bulletin Board Server and Local Client --- .../CachedBulletinBoardClient.java | 312 ++++++++++++++---- .../LocalBulletinBoardClient.java | 36 +- .../SingleServerBulletinBoardClient.java | 4 +- .../ThreadedBulletinBoardSubscriber.java | 9 +- .../GenericSubscriptionClientTester.java | 5 +- .../LocalBulletinBoardClientTest.java | 2 +- .../sqlserver/BulletinBoardSQLServer.java | 46 ++- .../sqlserver/H2QueryProvider.java | 53 ++- .../sqlserver/MySQLQueryProvider.java | 12 +- .../bulletinboard/BulletinBoardClient.java | 4 +- .../BulletinBoardMessageDeleter.java | 30 ++ .../DeletableBulletinBoardServer.java | 29 ++ ...etableSubscriptionBulletinBoardClient.java | 7 + .../SubscriptionAsyncBulletinBoardClient.java | 7 - .../SubscriptionBulletinBoardClient.java | 7 + 15 files changed, 448 insertions(+), 115 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/DeletableBulletinBoardServer.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/DeletableSubscriptionBulletinBoardClient.java delete mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionBulletinBoardClient.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index 96ba76d..6aac297 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -1,168 +1,338 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.ListeningScheduledExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.*; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.concurrent.Executors; /** * Created by Arbel Deutsch Peled on 03-Mar-16. * This is a full-fledged implementation of a Bulletin Board Client * It provides asynchronous access to several remote servers, as well as a local cache - * Read/write operations are performed on the local server + * Read operations are performed on the local server + * Batch reads are performed on the local server and, if they fail, also on the remote servers + * Write operations are performed first on the local server and then on the remotes * After any read is carried out, a subscription is made for the specific query to make sure the local DB will be updated * The database also employs a synchronizer which makes sure local data is sent to the remote servers */ -public class CachedBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient { +public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClient { - private final BulletinBoardClient localClient; + private final AsyncBulletinBoardClient localClient; private AsyncBulletinBoardClient remoteClient; private BulletinBoardSubscriber subscriber; - private final int threadPoolSize; - private final long failDelayInMilliseconds; - private final long subscriptionIntervalInMilliseconds; + private class SubscriptionStoreCallback implements FutureCallback> { - public CachedBulletinBoardClient(BulletinBoardClient localClient, - int threadPoolSize, - long failDelayInMilliseconds, - long subscriptionIntervalInMilliseconds) - throws IllegalAccessException, InstantiationException { + private final FutureCallback callback; + + public SubscriptionStoreCallback(){ + callback = null; + } + + public SubscriptionStoreCallback(FutureCallback callback){ + this.callback = callback; + } + + @Override + public void onSuccess(List result) { + for (BulletinBoardMessage msg : result) { + try { + localClient.postMessage(msg); + } catch (CommunicationException ignored) { + // TODO: log + } + } + } + + @Override + public void onFailure(Throwable t) { + if (callback != null) { + callback.onFailure(t); // This is some hard error that cannot be dealt with + } + } + + } + + /** + * Creates a Cached Client + * Assumes all parameters are initialized + * @param localClient is a Client for the local instance + * @param remoteClient is a Client for the remote instance(s); Should have endless retries for post operations + * @param subscriber is a subscription service to the remote instance(s) + */ + public CachedBulletinBoardClient(AsyncBulletinBoardClient localClient, + AsyncBulletinBoardClient remoteClient, + BulletinBoardSubscriber subscriber) { this.localClient = localClient; - this.threadPoolSize = threadPoolSize; - this.failDelayInMilliseconds = failDelayInMilliseconds; - this.subscriptionIntervalInMilliseconds = subscriptionIntervalInMilliseconds; - - remoteClient = new ThreadedBulletinBoardClient(); + this.remoteClient = remoteClient; + this.subscriber = subscriber; } @Override - public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback) { - return null; - } + public MessageID postMessage(final BulletinBoardMessage msg, final FutureCallback callback) { - @Override - public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { - return null; - } + return localClient.postMessage(msg, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postMessage(msg, callback); + } - @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override - public void postBatchData(byte[] signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + public MessageID postBatch(final CompleteBatch completeBatch, final FutureCallback callback) { + + return localClient.postBatch(completeBatch, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postBatch(completeBatch, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override - public void postBatchData(byte[] signerId, int batchId, List batchDataList, FutureCallback callback) { + public void beginBatch(final BeginBatchMessage beginBatchMessage, final FutureCallback callback) { + + localClient.beginBatch(beginBatchMessage, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.beginBatch(beginBatchMessage, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override - public void postBatchData(ByteString signerId, int batchId, List batchDataList, int startPosition, FutureCallback callback) { + public void postBatchData(final byte[] signerId, final int batchId, final List batchDataList, + final int startPosition, final FutureCallback callback) { + + localClient.postBatchData(signerId, batchId, batchDataList, startPosition, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postBatchData(signerId, batchId, batchDataList, startPosition, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override - public void postBatchData(ByteString signerId, int batchId, List batchDataList, FutureCallback callback) { + public void postBatchData(final byte[] signerId, final int batchId, final List batchDataList, final FutureCallback callback) { + + localClient.postBatchData(signerId, batchId, batchDataList, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postBatchData(signerId, batchId, batchDataList, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + public void postBatchData(final ByteString signerId, final int batchId, final List batchDataList, + final int startPosition, final FutureCallback callback) { + + localClient.postBatchData(signerId, batchId, batchDataList, startPosition, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postBatchData(signerId, batchId, batchDataList, startPosition, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); + + } + + @Override + public void postBatchData(final ByteString signerId, final int batchId, final List batchDataList, final FutureCallback callback) { + + localClient.postBatchData(signerId, batchId, batchDataList, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.postBatchData(signerId, batchId, batchDataList, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); + + } + + @Override + public void closeBatch(final CloseBatchMessage closeBatchMessage, final FutureCallback callback) { + + localClient.closeBatch(closeBatchMessage, new FutureCallback() { + @Override + public void onSuccess(Boolean result) { + remoteClient.closeBatch(closeBatchMessage, callback); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + }); } @Override public void getRedundancy(MessageID id, FutureCallback callback) { - } - - @Override - public void readMessages(MessageFilterList filterList, FutureCallback> callback) { + remoteClient.getRedundancy(id, callback); } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + public void readMessages(MessageFilterList filterList, final FutureCallback> callback) { + + localClient.readMessages(filterList, callback); + + subscriber.subscribe(filterList, new SubscriptionStoreCallback(callback)); + + } + + @Override + public void readBatch(final BatchSpecificationMessage batchSpecificationMessage, final FutureCallback callback) { + + localClient.readBatch(batchSpecificationMessage, new FutureCallback() { + @Override + public void onSuccess(CompleteBatch result) { + callback.onSuccess(result); // Read from local client was successful + } + + @Override + public void onFailure(Throwable t) { + + // Read from local unsuccessful: try to read from remote + + remoteClient.readBatch(batchSpecificationMessage, new FutureCallback() { + + @Override + public void onSuccess(CompleteBatch result) { + + // Read from remote was successful: store in local and return result + + localClient.postBatch(result, new FutureCallback() { + @Override + public void onSuccess(Boolean result) {} + @Override + public void onFailure(Throwable t) {} + }); + + callback.onSuccess(result); + + } + + @Override + public void onFailure(Throwable t) { + + // Read from remote was unsuccessful: report error + callback.onFailure(t); + + } + + }); + + } + + }); } @Override public void querySync(SyncQuery syncQuery, FutureCallback callback) { + localClient.querySync(syncQuery, callback); + } @Override - public void init(BulletinBoardClientParams clientParams) { - - remoteClient.init(clientParams); - - ListeningScheduledExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadPoolSize)); - - List subscriberClients = new ArrayList<>(clientParams.getBulletinBoardAddressCount()); - - for (String address : clientParams.getBulletinBoardAddressList()){ - - SubscriptionAsyncBulletinBoardClient newClient = - new SingleServerBulletinBoardClient(executorService, failDelayInMilliseconds, subscriptionIntervalInMilliseconds); - - newClient.init(clientParams.toBuilder().clearBulletinBoardAddress().addBulletinBoardAddress(address).build()); - - subscriberClients.add(newClient); - - } - - subscriber = new ThreadedBulletinBoardSubscriber(subscriberClients, localClient); - - } + /** + * This is a stub method + * All resources are assumed to be initialized + */ + public void init(BulletinBoardClientParams clientParams) {} @Override public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { - return null; + localClient.postMessage(msg); + return remoteClient.postMessage(msg); } @Override public float getRedundancy(MessageID id) { - return 0; + return remoteClient.getRedundancy(id); } @Override public List readMessages(MessageFilterList filterList) { - return null; + subscriber.subscribe(filterList, new SubscriptionStoreCallback()); + return localClient.readMessages(filterList); } @Override - public SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException { - return null; + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException { + return localClient.generateSyncQuery(generateSyncQueryParams); } @Override public void close() { - + localClient.close(); + remoteClient.close(); } @Override public void subscribe(MessageFilterList filterList, FutureCallback> callback) { - + subscriber.subscribe(filterList, callback); } @Override public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { + subscriber.subscribe(filterList, startEntry, callback); + } + + public int syncStatus(){ + return 0; + } + + public void reSync(){ } -} + +} \ No newline at end of file diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index df3e196..1f56690 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -22,14 +22,14 @@ import java.util.concurrent.TimeUnit; /** * Created by Arbel Deutsch Peled on 15-Mar-16. - * This client is to be used mainly for testing. - * It wraps a BulletinBoardServer in an asynchronous client. + * This client wraps a BulletinBoardServer in an asynchronous client. + * It is meant to be used as a local cache handler and for testing purposes. * This means the access to the server is direct (via method calls) instead of through a TCP connection. * The client implements both synchronous and asynchronous method calls, but calls to the server itself are performed synchronously. */ -public class LocalBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient{ +public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBoardClient { - private final BulletinBoardServer server; + private final DeletableBulletinBoardServer server; private final ListeningScheduledExecutorService executorService; private final BatchDigest digest; private final int subsrciptionDelay; @@ -40,7 +40,7 @@ public class LocalBulletinBoardClient implements SubscriptionAsyncBulletinBoardC * @param threadNum is the number of concurrent threads to allocate for the client * @param subscriptionDelay is the required delay between subscription calls in milliseconds */ - public LocalBulletinBoardClient(BulletinBoardServer server, int threadNum, int subscriptionDelay) { + public LocalBulletinBoardClient(DeletableBulletinBoardServer server, int threadNum, int subscriptionDelay) { this.server = server; this.executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadNum)); this.digest = new GenericBatchDigest(new SHA256Digest()); @@ -517,8 +517,30 @@ public class LocalBulletinBoardClient implements SubscriptionAsyncBulletinBoardC } @Override - public SyncQuery generateSyncQuery(GenerateSyncQueryParams GenerateSyncQueryParams) throws CommunicationException { - return server.generateSyncQuery(GenerateSyncQueryParams); + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException { + return server.generateSyncQuery(generateSyncQueryParams); + } + + @Override + public void deleteMessage(MessageID msgID, FutureCallback callback) { + + try { + callback.onSuccess(server.deleteMessage(msgID).getValue()); + } catch (CommunicationException e) { + callback.onFailure(e); + } + + } + + @Override + public void deleteMessage(long entryNum, FutureCallback callback) { + + try { + callback.onSuccess(server.deleteMessage(entryNum).getValue()); + } catch (CommunicationException e) { + callback.onFailure(e); + } + } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 34531cf..f12430d 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -7,12 +7,10 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.BulletinBoardClientParams; import meerkat.util.BulletinBoardUtils; -import javax.ws.rs.NotFoundException; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; @@ -30,7 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger; * If the list of servers contains more than one server: the server actually used is the first one * The class further implements a delayed access to the server after a communication error occurs */ -public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements SubscriptionAsyncBulletinBoardClient { +public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements SubscriptionBulletinBoardClient { private final int MAX_RETRIES = 11; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java index cf8d47d..ca8ef84 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java @@ -8,7 +8,6 @@ import meerkat.util.BulletinBoardUtils; import static meerkat.protobuf.BulletinBoardAPI.FilterType.*; -import java.sql.Time; import java.util.*; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; @@ -19,11 +18,11 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber { - protected final Collection clients; + protected final Collection clients; protected final BulletinBoardClient localClient; - protected Iterator clientIterator; - protected SubscriptionAsyncBulletinBoardClient currentClient; + protected Iterator clientIterator; + protected SubscriptionBulletinBoardClient currentClient; private long lastServerSwitchTime; @@ -32,7 +31,7 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber private static final Float[] BREAKPOINTS = {0.5f, 0.75f, 0.9f, 0.95f, 0.99f, 0.999f}; - public ThreadedBulletinBoardSubscriber(Collection clients, BulletinBoardClient localClient) { + public ThreadedBulletinBoardSubscriber(Collection clients, BulletinBoardClient localClient) { this.clients = clients; this.localClient = localClient; diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java index a91f8d6..4a5fe62 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java @@ -17,7 +17,6 @@ import java.util.*; import java.util.concurrent.Semaphore; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.startsWith; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -38,7 +37,7 @@ public class GenericSubscriptionClientTester { private static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; private static String CERT3_PEM_EXAMPLE = "/certs/enduser-certs/user3.crt"; - private SubscriptionAsyncBulletinBoardClient bulletinBoardClient; + private SubscriptionBulletinBoardClient bulletinBoardClient; private Random random; private BulletinBoardMessageGenerator generator; @@ -46,7 +45,7 @@ public class GenericSubscriptionClientTester { private Semaphore jobSemaphore; private Vector thrown; - public GenericSubscriptionClientTester(SubscriptionAsyncBulletinBoardClient bulletinBoardClient){ + public GenericSubscriptionClientTester(SubscriptionBulletinBoardClient bulletinBoardClient){ this.bulletinBoardClient = bulletinBoardClient; diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index d2039ae..0ab5c67 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -48,7 +48,7 @@ public class LocalBulletinBoardClientTest { throw new CommunicationException(e.getCause() + " " + e.getMessage()); } - BulletinBoardServer server = new BulletinBoardSQLServer(queryProvider); + DeletableBulletinBoardServer server = new BulletinBoardSQLServer(queryProvider); server.init(DB_NAME); LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM, SUBSRCIPTION_DELAY); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index ab82ab1..cebeb8e 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -6,6 +6,7 @@ import java.util.*; import com.google.protobuf.*; import com.google.protobuf.Timestamp; +import com.sun.org.apache.xpath.internal.operations.Bool; import meerkat.bulletinboard.*; import meerkat.bulletinboard.sqlserver.mappers.*; import static meerkat.bulletinboard.BulletinBoardConstants.*; @@ -16,6 +17,7 @@ import meerkat.comm.MessageOutputStream; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; @@ -38,7 +40,7 @@ import org.springframework.jdbc.support.KeyHolder; /** * This is a generic SQL implementation of the BulletinBoardServer API. */ -public class BulletinBoardSQLServer implements BulletinBoardServer{ +public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ /** * This interface provides the required implementation-specific data to enable an access to an actual SQL server. @@ -67,6 +69,16 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ new int[] {Types.BLOB, Types.TIMESTAMP, Types.BLOB} ), + DELETE_MSG_BY_ENTRY( + new String[] {"EntryNum"}, + new int[] {Types.INTEGER} + ), + + DELETE_MSG_BY_ID( + new String[] {"MsgId"}, + new int[] {Types.BLOB} + ), + INSERT_NEW_TAG( new String[] {"Tag"}, new int[] {Types.VARCHAR} @@ -529,6 +541,38 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return postMessage(msg, true); // Perform a post and check the signature for authenticity } + @Override + public BoolMsg deleteMessage(MessageID msgID) throws CommunicationException { + + String sql = sqlQueryProvider.getSQLString(QueryType.DELETE_MSG_BY_ID); + Map namedParameters = new HashMap(); + + namedParameters.put(QueryType.DELETE_MSG_BY_ID.getParamName(0),msgID); + + int affectedRows = jdbcTemplate.update(sql, namedParameters); + + //TODO: Log + + return BoolMsg.newBuilder().setValue(affectedRows > 0).build(); + + } + + @Override + public BoolMsg deleteMessage(long entryNum) throws CommunicationException { + + String sql = sqlQueryProvider.getSQLString(QueryType.DELETE_MSG_BY_ENTRY); + Map namedParameters = new HashMap(); + + namedParameters.put(QueryType.DELETE_MSG_BY_ENTRY.getParamName(0),entryNum); + + int affectedRows = jdbcTemplate.update(sql, namedParameters); + + //TODO: Log + + return BoolMsg.newBuilder().setValue(affectedRows > 0).build(); + + } + /** * This is a container class for and SQL string builder and a MapSqlParameterSource to be used with it diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index 44a55da..bef6d68 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -30,19 +30,28 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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)"; + return MessageFormat.format( + "INSERT INTO SignatureTable (EntryNum, SignerId, Signature)" + + " SELECT DISTINCT :{0} AS Entry, :{1} AS Id, :{2} AS Sig FROM UtilityTable AS Temp" + + " WHERE NOT EXISTS" + + " (SELECT 1 FROM SignatureTable AS SubTable WHERE SubTable.EntryNum = :{0} AND SubTable.SignerId = :{1})", + QueryType.ADD_SIGNATURE.getParamName(0), + QueryType.ADD_SIGNATURE.getParamName(1), + QueryType.ADD_SIGNATURE.getParamName(2)); 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)"; + return MessageFormat.format( + "INSERT INTO MsgTagTable (TagId, EntryNum)" + + " SELECT DISTINCT TagTable.TagId, :{0} AS NewEntry FROM TagTable WHERE Tag = :{1}" + + " AND NOT EXISTS (SELECT 1 FROM MsgTagTable AS SubTable WHERE SubTable.TagId = TagTable.TagId" + + " AND SubTable.EntryNum = :{0})", + QueryType.CONNECT_TAG.getParamName(0), + QueryType.CONNECT_TAG.getParamName(1)); case FIND_MSG_ID: - return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId"; + return MessageFormat.format( + "SELECT EntryNum From MsgTable WHERE MsgId = :{0}", + QueryType.FIND_MSG_ID.getParamName(0)); case FIND_TAG_ID: return MessageFormat.format( @@ -59,14 +68,32 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider return "SELECT MsgTable.EntryNum, MsgTable.MsgId, MsgTable.ExactTime FROM MsgTable"; case GET_SIGNATURES: - return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum"; + return MessageFormat.format( + "SELECT Signature FROM SignatureTable WHERE EntryNum = :{0}", + QueryType.GET_SIGNATURES.getParamName(0)); case INSERT_MSG: - return "INSERT INTO MsgTable (MsgId, Msg, ExactTime) VALUES(:MsgId,:Msg,:TimeStamp)"; + 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 DELETE_MSG_BY_ENTRY: + return MessageFormat.format( + "DELETE FROM MsgTable WHERE EntryNum = :{0}", + QueryType.DELETE_MSG_BY_ENTRY.getParamName(0)); + + case DELETE_MSG_BY_ID: + return MessageFormat.format( + "DELETE FROM MsgTable WHERE MsgId = :{0}", + QueryType.DELETE_MSG_BY_ID.getParamName(0)); 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)"; + return MessageFormat.format( + "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE" + + " NOT EXISTS (SELECT 1 FROM TagTable AS SubTable WHERE SubTable.Tag = :{0})", + QueryType.INSERT_NEW_TAG.getParamName(0)); case GET_LAST_MESSAGE_ENTRY: return "SELECT MAX(MsgTable.EntryNum) FROM MsgTable"; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index adf96a4..ad3df68 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -1,7 +1,5 @@ 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; @@ -81,6 +79,16 @@ public class MySQLQueryProvider implements SQLQueryProvider { QueryType.INSERT_MSG.getParamName(1), QueryType.INSERT_MSG.getParamName(2)); + case DELETE_MSG_BY_ENTRY: + return MessageFormat.format( + "DELETE IGNORE FROM MsgTable WHERE EntryNum = :{0}", + QueryType.DELETE_MSG_BY_ENTRY.getParamName(0)); + + case DELETE_MSG_BY_ID: + return MessageFormat.format( + "DELETE IGNORE FROM MsgTable WHERE MsgId = :{0}", + QueryType.DELETE_MSG_BY_ID.getParamName(0)); + case INSERT_NEW_TAG: return MessageFormat.format( "INSERT IGNORE INTO TagTable(Tag) VALUES (:{0})", diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 245eddf..9d7d5b8 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -47,12 +47,12 @@ public interface BulletinBoardClient { /** * 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 + * @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; + SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException; /** * Closes all connections, if any. diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java new file mode 100644 index 0000000..6025719 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java @@ -0,0 +1,30 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +/** + * Created by Arbel Deutsch Peled on 13-Apr-16. + * This interface is meant to extend a BulletinBoardClient interface/class + * It provides it with the ability to delete messages from the Server + * This assumes the Server implements the {@link DeletableBulletinBoardServer} + */ +public interface BulletinBoardMessageDeleter { + + /** + * Deletes a message from a Bulletin Board Server + * @param msgID is the ID of the message to delete + * @param callback handles the result of the operation + */ + public void deleteMessage(MessageID msgID, FutureCallback callback); + + /** + * Deletes a message from the Bulletin Board + * Logs this action + * @param entryNum is the serial entry number of the message to delete + * @param callback handles the result of the operation + */ + public void deleteMessage(long entryNum, FutureCallback callback); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableBulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableBulletinBoardServer.java new file mode 100644 index 0000000..03e0c3f --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableBulletinBoardServer.java @@ -0,0 +1,29 @@ +package meerkat.bulletinboard; + +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +/** + * Created by Arbel Deutsch Peled on 13-Apr-16. + */ +public interface DeletableBulletinBoardServer extends BulletinBoardServer { + + /** + * Deletes a message from the Bulletin Board + * Logs this action + * @param msgID is the ID of the message to delete + * @return a BoolMsg containing the value TRUE if a message was deleted, FALSE if the message does not exist + * @throws CommunicationException in case of an error + */ + public BoolMsg deleteMessage(MessageID msgID) throws CommunicationException; + + /** + * Deletes a message from the Bulletin Board + * Logs this action + * @param entryNum is the serial entry number of the message to delete + * @return a BoolMsg containing the value TRUE if a message was deleted, FALSE if the message does not exist + * @throws CommunicationException in case of an error + */ + public BoolMsg deleteMessage(long entryNum) throws CommunicationException; + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableSubscriptionBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableSubscriptionBulletinBoardClient.java new file mode 100644 index 0000000..acc29fe --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/DeletableSubscriptionBulletinBoardClient.java @@ -0,0 +1,7 @@ +package meerkat.bulletinboard; + +/** + * Created by Arbel Deutsch Peled on 13-Apr-16. + */ +public interface DeletableSubscriptionBulletinBoardClient extends SubscriptionBulletinBoardClient, BulletinBoardMessageDeleter { +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java deleted file mode 100644 index b07e655..0000000 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionAsyncBulletinBoardClient.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.bulletinboard; - -/** - * Created by Arbel Deutsch Peled on 03-Mar-16. - */ -public interface SubscriptionAsyncBulletinBoardClient extends AsyncBulletinBoardClient, BulletinBoardSubscriber { -} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionBulletinBoardClient.java new file mode 100644 index 0000000..5577bac --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/SubscriptionBulletinBoardClient.java @@ -0,0 +1,7 @@ +package meerkat.bulletinboard; + +/** + * Created by Arbel Deutsch Peled on 03-Mar-16. + */ +public interface SubscriptionBulletinBoardClient extends AsyncBulletinBoardClient, BulletinBoardSubscriber { +} From 1f8df95895e7f17d709fe299200072a11c2fdf45 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Thu, 14 Apr 2016 03:34:54 +0300 Subject: [PATCH 048/106] More refactoring for tests and protocol -- user class now handles all messages synchronously (in the main thread); concurrency is now simpler) --- distributed-key-generation/build.gradle | 3 + .../meerkat/crypto/dkg/comm/MailHandler.java | 53 -- .../crypto/dkg/comm/MessageHandler.java | 67 ++- .../crypto/dkg/feldman/MailHandler.java | 21 - .../meerkat/crypto/dkg/feldman/Protocol.java | 59 +- .../java/meerkat/crypto/dkg/feldman/User.java | 530 +++++++++--------- .../meerkat/crypto/dkg/gjkr/MailHandler.java | 36 -- .../java/meerkat/crypto/dkg/gjkr/User.java | 411 +++++++------- .../src/main/proto/meerkat/DKG.proto | 12 +- .../crypto/dkg/feldman/DKGMaliciousUser.java | 2 +- .../meerkat/crypto/dkg/feldman/DKGTest.java | 16 +- .../crypto/dkg/feldman/DKGUserImplAbort.java | 2 +- .../dkg/gjkr/SDKGMaliciousUserImpl.java | 2 +- .../meerkat/crypto/dkg/gjkr/SDKGTest.java | 129 +++-- .../crypto/dkg/gjkr/SDKGUserImplAbort.java | 18 +- .../meerkat/crypto/utils/ChannelImpl.java | 111 ---- .../src/main/java/meerkat/comm}/Channel.java | 6 +- .../src/main/proto/meerkat/comm.proto | 13 + .../test/java/meerkat/comm/ChannelImpl.java | 96 ++++ 19 files changed, 780 insertions(+), 807 deletions(-) delete mode 100644 distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java delete mode 100644 distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java delete mode 100644 distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java delete mode 100644 distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java rename {distributed-key-generation/src/main/java/meerkat/crypto/utils => meerkat-common/src/main/java/meerkat/comm}/Channel.java (89%) create mode 100644 meerkat-common/src/main/proto/meerkat/comm.proto create mode 100644 meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java diff --git a/distributed-key-generation/build.gradle b/distributed-key-generation/build.gradle index 074667f..8f0a397 100644 --- a/distributed-key-generation/build.gradle +++ b/distributed-key-generation/build.gradle @@ -49,6 +49,9 @@ dependencies { // 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.+' diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java deleted file mode 100644 index 5cd1be0..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package meerkat.crypto.dkg.comm; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.utils.Channel; -import meerkat.protobuf.DKG; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Created by Tzlil on 2/14/2016. - * - * an implementation of ReceiverCallback - */ -public abstract class MailHandler implements Channel.ReceiverCallback{ - final Logger logger = LoggerFactory.getLogger(getClass()); - - /** - * fixed value for broadcasting - */ - public static final int BROADCAST = 0; - - /** - * message handler - */ - private MessageHandler messageHandler; - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler){ - this.messageHandler = messageHandler; - } - - /** - * Was this broadcastMessage was received by broadcast channel - * @param broadcastMessage - * @return broadcastMessage user destination == BROADCAST - */ - public boolean isBroadcast(DKG.BroadcastMessage broadcastMessage){ - return broadcastMessage.getDestination() == BROADCAST; - } - - @Override - public void receiveMail(DKG.BroadcastMessage envelope) { - try { - messageHandler.handleMessage(envelope); - } catch (InvalidProtocolBufferException e) { - logger.warn("Received invalid protocol buffer from channel", e); - } - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java index 4927e94..02c751b 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java @@ -1,50 +1,47 @@ package meerkat.crypto.dkg.comm; import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKG; +import meerkat.comm.Channel; +import meerkat.protobuf.Comm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by Tzlil on 2/14/2016. - * an interface for handling received messages + * + * an implementation of ReceiverCallback */ -public interface MessageHandler { +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 */ - void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException; -// -// /** -// * handle share message -// */ -// void handleShareMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle commitment message -// */ -// void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle complaint message -// */ -// void handleComplaintMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle done message -// */ -// void handleDoneMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle answer message -// */ -// void handleAnswerMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle abort message -// */ -// void handleAbortMessage(int sender, boolean isBroadcast, Message message); + 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); + } + } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java deleted file mode 100644 index dabfa17..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package meerkat.crypto.dkg.feldman; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKG; - -/** - * Created by Tzlil on 2/29/2016. - * an extension of MailHandler matching joint feldman protocol - */ -public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler) { - super(messageHandler); - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index 74d35d4..d81c75a 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; @@ -171,7 +171,9 @@ public class Protocol extends VerifiableSecretSharing { */ public boolean isValidShare(int i){ Party party = parties[i - 1]; - return isValidShare(party.share,party.commitments,id); + synchronized (parties[i - 1]) { + return isValidShare(party.share, party.commitments, id); + } } /** @@ -232,7 +234,7 @@ public class Protocol extends VerifiableSecretSharing { */ public void answerAllComplainingPlayers(){ ComplaintState[] complaints = parties[id - 1].complaints; - for (int i = 1; i <= n ; i++) { + for (int i = 1; i <= n; i++) { switch (complaints[i - 1]) { case Waiting: broadcastComplaintAnswer(i); @@ -241,6 +243,7 @@ public class Protocol extends VerifiableSecretSharing { break; } } + } /** @@ -252,26 +255,28 @@ public class Protocol extends VerifiableSecretSharing { Set QUAL = new HashSet(); boolean nonDisqualified; int counter; - for (int i = 1; i <= n; i++){ - 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; + 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) - break; - } - if(nonDisqualified && counter <= t){ - QUAL.add(i); + if (nonDisqualified && counter <= t) { + QUAL.add(i); + } } } return QUAL; @@ -285,7 +290,9 @@ public class Protocol extends VerifiableSecretSharing { public T calcY(Set QUAL){ T y = group.zero(); for (int i : QUAL) { - y = group.add(y , parties[i - 1].commitments.get(0)); + synchronized (parties[i - 1]) { + y = group.add(y, parties[i - 1].commitments.get(0)); + } } return y; } @@ -301,7 +308,9 @@ public class Protocol extends VerifiableSecretSharing { for (int k = 0; k <= t; k++){ value = group.zero(); for (int i : QUAL) { - value = group.add(value, parties[i - 1].commitments.get(k)); + synchronized (parties[i - 1]) { + value = group.add(value, parties[i - 1].commitments.get(k)); + } } commitments.add(k,value); } @@ -315,7 +324,9 @@ public class Protocol extends VerifiableSecretSharing { public Polynomial.Point calcShare(Set QUAL){ BigInteger xj = BigInteger.ZERO; for (int i : QUAL) { - xj = xj.add(parties[i - 1].share.y); + synchronized (parties[i - 1]) { + xj = xj.add(parties[i - 1].share.y); + } } return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index 4e4f155..6563dfd 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -1,16 +1,23 @@ package meerkat.crypto.dkg.feldman; import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.utils.Channel; +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 com.google.protobuf.Message; +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; @@ -25,7 +32,8 @@ import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; * 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 implements Runnable{ +public class User implements Runnable { + final Logger logger = LoggerFactory.getLogger(getClass()); /** * joint feldman protocol object @@ -59,10 +67,6 @@ public class User implements Runnable{ */ protected final int n; - /** - * mail handler registered to channel as ReceiverCallback - */ - protected meerkat.crypto.dkg.comm.MailHandler mailHandler; /** * channel object @@ -96,6 +100,8 @@ public class User implements Runnable{ */ protected T y; + protected BlockingQueue receiveQueue; + /** * constructor * @param dkg joint feldman protocol object @@ -120,14 +126,45 @@ public class User implements Runnable{ this.share = null; this.y = null; + this.receiveQueue = new LinkedBlockingDeque<>(); + } /** - * create MailHandler and register it as ReceiverCallback + * create MessageHandler and register it as ReceiverCallback */ - protected void registerReceiverCallback(){ - this.mailHandler = new MailHandler(new MessageHandler()); - channel.registerReceiverCallback(mailHandler); + 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(); + } } /** @@ -140,37 +177,34 @@ public class User implements Runnable{ dkg.sendSecrets(); } - /** - * wait for all shares and commitments will arrive from other parties + * Check if all shares and commitments have arrived from other parties */ - protected void waitUntilStageOneCompleted(){ - // wait for parties' share - for (int i = 0 ; i < n ; i++){ - synchronized (parties[i]) { - while (parties[i].share == null && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } + 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; } } } - // wait for parties' commitments - for (int i = 0 ; i < n ; i++){ - for (int k = 0 ; k <= t ; k++) { - synchronized (parties[i]) { - while (parties[i].commitments.get(k) == null && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + 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; } /** @@ -185,25 +219,28 @@ public class User implements Runnable{ channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); } - /** * wait until all other parties done complaining by receiving done message */ protected void waitUntilStageTwoCompleted(){ - for (int i = 0 ; i < n ; i++){ - synchronized (parties[i]) { - while (!parties[i].doneFlag && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + 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. @@ -213,20 +250,11 @@ public class User implements Runnable{ */ protected void stage3(){ dkg.answerAllComplainingPlayers(); + // wait until there is no complaint waiting for answer - for (int i = 0; i < n; i++){ - for (int j = 0; j < n; j++){ - synchronized (parties[i]) { - while (parties[i].complaints[j].equals(Protocol.ComplaintState.Waiting) && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + while (!stop && !haveReceivedAllStage3ComplaintAnswers()) + waitAndHandleReceivedMessages(); + this.QUAL = dkg.calcQUAL(); } @@ -245,15 +273,23 @@ public class User implements Runnable{ @Override public void run() { this.runThread = Thread.currentThread(); - stage1(); - waitUntilStageOneCompleted(); - if (stop) return; - stage2(); - waitUntilStageTwoCompleted(); - if (stop) return; - stage3(); - if (stop) return; - stage4(); + // 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); + } } /** @@ -360,199 +396,193 @@ public class User implements Runnable{ } /** - * an implementation of MessageHandler + * commitment message is valid if: + * 1. it was received in broadcast chanel + * 2. the sender didn't sent this commitment before */ - public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler { + 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; + } - /** - * 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; - /** - * 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; - } + /** + * 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(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK); - } + /** + * 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(); - /** - * 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); - } + 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); + } - @Override - public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException { - int sender = envelope.getSender(); - boolean isBroadcast = !envelope.getIsPrivate(); - DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); + 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 COMMITMENT: - /** - * saves the commitment - */ - DKG.CommitmentMessage commitmentMessage = msg.getCommitment(); - if (isValidCommitmentMessage(sender, isBroadcast, commitmentMessage)) { - int i = sender - 1; - int k = commitmentMessage.getK(); - synchronized (parties[i]) { - parties[i].commitments.set(k, extractCommitment(commitmentMessage)); - parties[i].notify(); - } + 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; } - break; - - - case SHARE: - /** - * saves the secret - */ - DKG.ShareMessage secretMessage = msg.getShare(); - if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - Polynomial.Point secret = extractShare(id,secretMessage.getShare()); - synchronized (parties[i -1]) { - parties[i - 1].share = secret; - parties[i - 1].notify(); - } + if (j == id) { + parties[i - 1].share = secret; } - break; + } + 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; - case DONE: - - /** - * marks that the sender was finished sending all his complaints - */ - if(isValidDoneMessage(sender,isBroadcast)) { - synchronized (parties[sender - 1]) { - parties[sender - 1].doneFlag = true; - parties[sender - 1].notify(); - } - } - break; - - case COMPLAINT: - /** - * marks that the sender was complained against id - */ - DKG.IDMessage complaintMessage = msg.getId(); - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - synchronized (parties[j - 1]) { - parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; - parties[j - 1].notify(); - } - } - 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 - */ - secretMessage = msg.getShare(); - if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - Polynomial.Point secret = extractShare(j,secretMessage.getShare()); - synchronized (parties[i - 1]) { - 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; - } - parties[i - 1].notify(); - } - } - break; - case ABORT: - /** - * marks that the sender was aborted - */ - synchronized (parties[sender - 1]) { - parties[sender - 1].aborted = true; - parties[sender - 1].notify(); - } - 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()); } } + + /** + * 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()); + } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java deleted file mode 100644 index 36f970e..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package meerkat.crypto.dkg.gjkr; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKG; - -/** - * Created by Tzlil on 2/29/2016. - * an extension of MailHandler matching gjkr protocl - */ -public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { - - /** - * flag that indicants whether the - * current run achieved stage 4 of the protocol or not - */ - private boolean isStage4; - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler) { - super(messageHandler); - this.isStage4 = false; - } - - /** - * setter - * @param stage4 - */ - public void setStage4(boolean stage4) { - isStage4 = stage4; - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java index 6a3e0a4..5c1b418 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java @@ -3,10 +3,10 @@ package meerkat.crypto.dkg.gjkr; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; -import com.google.protobuf.Message; +import meerkat.protobuf.Comm; import meerkat.protobuf.DKG; import java.math.BigInteger; @@ -38,10 +38,7 @@ public class User extends meerkat.crypto.dkg.feldman.User { */ protected final Protocol sdkg; - /** - * message handler - */ - private MessageHandler messageHandler; + boolean isStage4; /** * constructor @@ -55,13 +52,6 @@ public class User extends meerkat.crypto.dkg.feldman.User { this.parties = sdkg.getParties(); } - @Override - protected void registerReceiverCallback() { - this.messageHandler = new MessageHandler(); - this.mailHandler = new MailHandler(messageHandler); - this.channel.registerReceiverCallback(mailHandler); - } - /** * stage1 according to the protocol * 1. Pi broadcasts Cik=Aik*Bik for k = 0,...,t. @@ -73,6 +63,8 @@ public class User extends meerkat.crypto.dkg.feldman.User { sdkg.sendSecrets(); } + + @Override protected void waitUntilStageOneCompleted() { super.waitUntilStageOneCompleted(); @@ -98,40 +90,74 @@ public class User extends meerkat.crypto.dkg.feldman.User { 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 - for (int i : QUAL) { - for (int k = 0; k <= t; k++) { - synchronized (parties[i - 1]) { - while (parties[i - 1].commitments.get(k) == null && !parties[i - 1].aborted) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + 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 - for (int i : QUAL) { - synchronized ((parties[i - 1])) { - while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + while (!stop && !areAllQualPartiesDone()) + waitAndHandleReceivedMessages(); + + if (stop) + return; // broadcast i private secret foreach i in QUAL that aborted for (int i : QUAL) { @@ -140,19 +166,12 @@ public class User extends meerkat.crypto.dkg.feldman.User { } } // wait until at least t + 1 secrets will received foreach i in QUAL that aborted - for (int i : QUAL) { - synchronized ((parties[i - 1])) { - if (parties[i - 1].aborted) { - while (parties[i - 1].recoverSharesSet.size() <= t) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + while (!stop && !haveReceivedEnoughSecretShares()) + waitAndHandleReceivedMessages(); + + if (stop) + return; + Arithmetic arithmetic = new Fp(sdkg.getQ()); // restore necessary information for (int i = 0; i < n; i++) { @@ -177,11 +196,10 @@ public class User extends meerkat.crypto.dkg.feldman.User { } /** - * notifies mail handler and message handler that stage 4 was started + * notifies message handler and message handler that stage 4 was started */ protected void setStage4() { - this.messageHandler.isStage4 = true; - ((MailHandler) this.mailHandler).setStage4(true); + isStage4 = true; } @Override @@ -192,151 +210,150 @@ public class User extends meerkat.crypto.dkg.feldman.User { super.stage4(); } - private class MessageHandler extends meerkat.crypto.dkg.feldman.User.MessageHandler { - boolean isStage4; - - /** - * 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(DKG.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 - */ - 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 { - 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; - } + /** + * 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; + } + } + } \ No newline at end of file diff --git a/distributed-key-generation/src/main/proto/meerkat/DKG.proto b/distributed-key-generation/src/main/proto/meerkat/DKG.proto index 235f062..7d43a67 100644 --- a/distributed-key-generation/src/main/proto/meerkat/DKG.proto +++ b/distributed-key-generation/src/main/proto/meerkat/DKG.proto @@ -4,14 +4,6 @@ package meerkat; option java_package = "meerkat.protobuf"; -message BroadcastMessage { - int32 sender = 1; - int32 destination = 2; - bool is_private = 3; - - bytes payload = 5; -} - message Payload { enum Type { SHARE = 0; @@ -25,9 +17,11 @@ message Payload { ABORT = 8; } + + // Type of message in protocol Type type = 1; - oneof specific { + oneof payload_data { IDMessage id = 5; ShareMessage share = 6; CommitmentMessage commitment = 7; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java index ebd2ff6..78b70d4 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import java.math.BigInteger; import java.util.*; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java index 18b3674..f522a42 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java @@ -1,9 +1,9 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.ChannelImpl; +import meerkat.comm.ChannelImpl; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; @@ -71,13 +71,6 @@ public class DKGTest { assert (calculatedSecret.equals(testable.secret)); } - public void stopReceivers(Testable testable){ - ChannelImpl channel; - for (int i = 0 ; i < testable.dkgs.length ; i++){ - channel = (ChannelImpl)testable.dkgs[i].getChannel(); - channel.stop(); - } - } @Test public void test() throws Exception { @@ -85,7 +78,6 @@ public class DKGTest { for (int i = 0; i < tests; i++){ testable = new Testable(new Random()); oneTest(testable); - stopReceivers(testable); } } @@ -115,11 +107,11 @@ public class DKGTest { BigInteger s; Protocol dkg; this.secret = BigInteger.ZERO; - ChannelImpl channel; + ChannelImpl channels = new ChannelImpl(); ByteEncoder byteEncoder = new BigIntegerByteEncoder(); while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); - channel = new ChannelImpl(id,n); + Channel channel = channels.getChannel(id); s = randomIntModQ(random); dkg = new meerkat.crypto.dkg.feldman.Protocol(t, n, s, random, q, g, group, id,byteEncoder); dkgs[id - 1] = randomDKGUser(id,channel,dkg,random); diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java index 902d103..528ea9f 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.protobuf.DKG; import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java index f72b00a..baf1a81 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.gjkr; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import java.math.BigInteger; import java.util.Random; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java index b5c4c9f..e4550f0 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java @@ -1,9 +1,9 @@ package meerkat.crypto.dkg.gjkr; -import meerkat.crypto.utils.ChannelImpl; +import meerkat.comm.ChannelImpl; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.dkg.feldman.DKGMaliciousUser; import meerkat.crypto.secretsharing.shamir.Polynomial; @@ -13,34 +13,45 @@ 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 { - int tests = 10; + 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 group = new Zpstar(p); Arithmetic arithmetic = new Fp(q); - int t = 9; + int t = 1; int n = 20; - + Random rand = new Random(1); 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.sdkgs.length ; i++){ + testable.futures[i] = executorService.submit(testable.sdkgs[i]); } - for (int i = 0; i < testable.threads.length ; i++){ - testable.threads[i].join(); + for (int i = 0; i < testable.futures.length ; i++){ + testable.futures[i].get(); } // got the right public value @@ -73,41 +84,45 @@ public class SDKGTest { assert (calculatedSecret.equals(testable.secret)); } - public void stopReceivers(Testable testable){ - ChannelImpl channel; - for (int i = 0 ; i < testable.sdkgs.length ; i++){ - channel = (ChannelImpl)testable.sdkgs[i].getChannel(); - channel.stop(); - } - } @Test public void test() throws Exception { Testable testable; - for (int i = 0; i < tests; i++) { - testable = new Testable(new Random()); + for (int i = 0; i < NUM_TESTS; i++) { + testable = new Testable(n, t, group, q, rand); oneTest(testable); - stopReceivers(testable); } } - class Testable{ + + static class Testable { Set valids; Set QUAL; Set aborted; Set malicious; User[] sdkgs; - Thread[] threads; + Future[] futures; BigInteger g; BigInteger h; BigInteger secret; + Group group; + int n; + int t; + BigInteger q; + Random random; + ChannelImpl channels = new ChannelImpl(); - public Testable(Random random) { + public Testable(int n, int t, Group 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(); this.QUAL = new HashSet(); this.aborted = new HashSet(); this.malicious = new HashSet(); - this.threads = new Thread[n]; + this.futures = new Future[n]; this.g = sampleGenerator(random); this.h = group.multiply(g,randomIntModQ(random)); ArrayList ids = new ArrayList(); @@ -123,10 +138,9 @@ public class SDKGTest { while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); s = randomIntModQ(random); - channel = new ChannelImpl(id,n); + channel = channels.getChannel(id); sdkg = new Protocol(t, n, s, random, q, g , h, group, id,encoder); - sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg,random); - threads[id - 1] = new Thread(sdkgs[id - 1]); + sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg); if(QUAL.contains(id)){ this.secret = this.secret.add(s).mod(q); } @@ -134,33 +148,44 @@ public class SDKGTest { } - public User randomSDKGUser(int id, Channel channel, Protocol sdkg, Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new User(sdkg,channel); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); + enum UserType { + HONEST, + FAILSTOP, + MALICIOUS, + } + + public User newSDKGUser(int id, Channel channel, Protocol sdkg, UserType userType) { + switch(userType) { + case HONEST: + valids.add(id); + QUAL.add(id); + return new User(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 User(sdkg,channel); - case 1:// abort - 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 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); - default: - return null; - } + } + return new SDKGUserImplAbort(sdkg,channel,abortStage); + + case MALICIOUS: + malicious.add(id); + Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); + Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); + return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); + + } + fail("Unknown user type"); + return null; + } + + public User randomSDKGUser(int id, Channel channel, Protocol 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); } } diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java index b067c1a..5b0e11b 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java @@ -1,7 +1,9 @@ package meerkat.crypto.dkg.gjkr; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.dkg.comm.MessageUtils; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; +import meerkat.protobuf.Comm; import meerkat.protobuf.DKG; /** @@ -9,6 +11,10 @@ import meerkat.protobuf.DKG; */ public class SDKGUserImplAbort extends User { + public static class AbortException extends RuntimeException { + + } + final int abortStage; int stage; public SDKGUserImplAbort(Protocol sdkg, Channel channel, int abortStage) { @@ -20,6 +26,7 @@ public class SDKGUserImplAbort extends User { private void abort(){ //stopReceiver(); channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT)); + throw new AbortException(); } @Override @@ -61,4 +68,13 @@ public class SDKGUserImplAbort extends User { } stage++; } + + @Override + public void run() { + try { + super.run(); + } catch (AbortException e) { + // Expected + } + } } diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java deleted file mode 100644 index dfb1bfb..0000000 --- a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package meerkat.crypto.utils; - -import com.google.protobuf.Message; -import meerkat.protobuf.DKG; - -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Created by Tzlil on 2/14/2016. - */ -// TODO: Change nane to network - -public class ChannelImpl implements Channel { - - public static int BROADCAST = 0; - private static ChannelImpl[] channels = null; - - protected final Queue mailbox; - protected final int id; - protected final int n; - protected Thread receiverThread; - - - public ChannelImpl(int id, int n) { - if (channels == null){ - channels = new ChannelImpl[n]; - } - this.mailbox = new ArrayBlockingQueue( n * n * n); - this.id = id; - this.n = n; - channels[id - 1] = this; - } - - @Override - public int getSourceId() { - return id; - } - - - @Override - public void sendMessage(int destUser, Message msg) { - if(destUser < 1 || destUser > n) - return; - ChannelImpl channel = channels[destUser - 1]; - if (channel == null) - return; - DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() - .setSender(id) - .setDestination(destUser) - .setIsPrivate(true) - .setPayload(msg.toByteString()) - .build(); - synchronized (channel.mailbox) { - channel.mailbox.add(broadcastMessage); - channel.mailbox.notify(); - } - } - - @Override - public void broadcastMessage(Message msg) { - ChannelImpl channel; - DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() - .setSender(id) - .setDestination(BROADCAST) - .setIsPrivate(false) - .setPayload(msg.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - channel = channels[i]; - synchronized (channel.mailbox) { - channel.mailbox.add(broadcastMessage); - channel.mailbox.notify(); - } - } - } - - public void stop(){ - try{ - receiverThread.interrupt(); - }catch (Exception e){ - //do nothing - } - } - - @Override - public void registerReceiverCallback(final ReceiverCallback callback) { - stop(); - receiverThread = new Thread(new Runnable() { - @Override - public void run() { - while (true){ - try { - synchronized (mailbox) { - while (!mailbox.isEmpty()) { - callback.receiveMail(mailbox.remove()); - } - mailbox.wait(); - } - } catch (InterruptedException e) { - //do nothing - } - } - } - }); - receiverThread.start(); - } - - - -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java b/meerkat-common/src/main/java/meerkat/comm/Channel.java similarity index 89% rename from distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java rename to meerkat-common/src/main/java/meerkat/comm/Channel.java index 97a6060..7dd74c1 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java +++ b/meerkat-common/src/main/java/meerkat/comm/Channel.java @@ -1,7 +1,7 @@ -package meerkat.crypto.utils; +package meerkat.comm; import com.google.protobuf.Message; -import meerkat.protobuf.DKG; +import meerkat.protobuf.Comm; /** * A generic communication channel that supports point-to-point and broadcast operation @@ -15,7 +15,7 @@ public interface Channel { public int getSourceId(); public interface ReceiverCallback { - public void receiveMail(DKG.BroadcastMessage envelope); + public void receiveMessage(Comm.BroadcastMessage envelope); } /** diff --git a/meerkat-common/src/main/proto/meerkat/comm.proto b/meerkat-common/src/main/proto/meerkat/comm.proto new file mode 100644 index 0000000..c509165 --- /dev/null +++ b/meerkat-common/src/main/proto/meerkat/comm.proto @@ -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; +} diff --git a/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java b/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java new file mode 100644 index 0000000..cfe32c2 --- /dev/null +++ b/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java @@ -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 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; + } + } + +} From 9ed728fca7637473b5d825d35e2fbccdde55e69c Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 14 Apr 2016 09:20:11 +0300 Subject: [PATCH 049/106] Added message counting ability to the server (but not to the client) Added synchronous CompleteBatch read by the client Started implementing the synchronizer Added support for null callbacks --- .../CachedBulletinBoardClient.java | 48 +++-- .../LocalBulletinBoardClient.java | 82 +++++++- .../bulletinboard/MultiServerWorker.java | 6 +- .../SimpleBulletinBoardClient.java | 65 ++++-- .../SimpleBulletinBoardSynchronizer.java | 188 ++++++++++++++++++ .../SingleServerBulletinBoardClient.java | 42 ++-- .../ThreadedBulletinBoardSubscriber.java | 13 +- .../sqlserver/BulletinBoardSQLServer.java | 42 ++-- .../webapp/BulletinBoardWebApp.java | 12 +- .../bulletinboard/BulletinBoardClient.java | 10 +- .../bulletinboard/BulletinBoardConstants.java | 1 + .../bulletinboard/BulletinBoardServer.java | 10 +- .../BulletinBoardSynchronizer.java | 74 ++++++- .../meerkat/bulletinboard/CompleteBatch.java | 33 ++- 14 files changed, 532 insertions(+), 94 deletions(-) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index 6aac297..c8b26c7 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -84,7 +84,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -101,7 +102,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -118,7 +120,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -136,7 +139,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -153,7 +157,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -171,7 +176,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -188,7 +194,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -205,7 +212,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } }); @@ -233,7 +241,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien localClient.readBatch(batchSpecificationMessage, new FutureCallback() { @Override public void onSuccess(CompleteBatch result) { - callback.onSuccess(result); // Read from local client was successful + if (callback != null) + callback.onSuccess(result); // Read from local client was successful } @Override @@ -255,7 +264,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien public void onFailure(Throwable t) {} }); - callback.onSuccess(result); + if (callback != null) + callback.onSuccess(result); } @@ -263,7 +273,8 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien public void onFailure(Throwable t) { // Read from remote was unsuccessful: report error - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } @@ -301,11 +312,16 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public List readMessages(MessageFilterList filterList) { + public List readMessages(MessageFilterList filterList) throws CommunicationException { subscriber.subscribe(filterList, new SubscriptionStoreCallback()); return localClient.readMessages(filterList); } + @Override + public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { + return localClient.readBatch(batchSpecificationMessage); + } + @Override public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException { return localClient.generateSyncQuery(generateSyncQueryParams); @@ -327,12 +343,4 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien subscriber.subscribe(filterList, startEntry, callback); } - public int syncStatus(){ - return 0; - } - - public void reSync(){ - - } - } \ No newline at end of file diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index 1f56690..30ae462 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -291,6 +291,31 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } + private class BatchDataReader implements Callable> { + + private final BatchSpecificationMessage batchSpecificationMessage; + + public BatchDataReader(BatchSpecificationMessage batchSpecificationMessage) { + this.batchSpecificationMessage = batchSpecificationMessage; + } + + @Override + public List call() throws Exception { + + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream outputStream = new MessageOutputStream<>(byteOutputStream); + server.readBatch(batchSpecificationMessage, outputStream); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BatchData.class); + + return inputStream.asList(); + + } + } + @Override public void readMessages(MessageFilterList filterList, FutureCallback> callback) { Futures.addCallback(executorService.submit(new MessageReader(filterList)), callback); @@ -310,7 +335,8 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public void onSuccess(List result) { // Report new messages to user - callback.onSuccess(result); + if (callback != null) + callback.onSuccess(result); MessageFilterList.Builder filterBuilder = filterList.toBuilder(); @@ -339,7 +365,8 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public void onFailure(Throwable t) { // Notify caller about failure and terminate subscription - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } @@ -503,7 +530,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public List readMessages(MessageFilterList filterList) { + public List readMessages(MessageFilterList filterList) throws CommunicationException{ try { @@ -511,7 +538,40 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo return reader.call(); } catch (Exception e){ - return null; + throw new CommunicationException("Error reading from server"); + } + + } + + @Override + public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_TAG) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(batchSpecificationMessage.getSignerId()) + .build()) + .build(); + + BulletinBoardMessage batchMessage = readMessages(filterList).get(0); + + BatchDataReader batchDataReader = new BatchDataReader(batchSpecificationMessage); + + try { + + List batchDataList = batchDataReader.call(); + return new CompleteBatch(batchMessage, batchDataList); + + } catch (Exception e) { + throw new CommunicationException("Error reading batch"); } } @@ -525,9 +585,12 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public void deleteMessage(MessageID msgID, FutureCallback callback) { try { - callback.onSuccess(server.deleteMessage(msgID).getValue()); + Boolean deleted = server.deleteMessage(msgID).getValue(); + if (callback != null) + callback.onSuccess(deleted); } catch (CommunicationException e) { - callback.onFailure(e); + if (callback != null) + callback.onFailure(e); } } @@ -536,9 +599,12 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public void deleteMessage(long entryNum, FutureCallback callback) { try { - callback.onSuccess(server.deleteMessage(entryNum).getValue()); + Boolean deleted = server.deleteMessage(entryNum).getValue(); + if (callback != null) + callback.onSuccess(deleted); } catch (CommunicationException e) { - callback.onFailure(e); + if (callback != null) + callback.onFailure(e); } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java index 7347f47..60327fa 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java @@ -74,7 +74,8 @@ public abstract class MultiServerWorker extends BulletinClientWorker extends BulletinClientWorker readMessages(MessageFilterList filterList) { - WebTarget webTarget; - Response response; - BulletinBoardMessageList messageList; - // Replace null filter list with blank one. if (filterList == null){ - filterList = MessageFilterList.newBuilder().build(); + filterList = MessageFilterList.getDefaultInstance(); } 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)); + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(db, filterList, 0); - messageList = response.readEntity(BulletinBoardMessageList.class); + List result = worker.call(); - if (messageList != null){ - return messageList.getMessageList(); - } + return result; - } catch (Exception e) {} + } catch (Exception ignored) {} + } + return null; + + } + + @Override + public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { + + // Create job with no retries for retrieval of the Bulletin Board Message that defines the batch + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_TAG) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.TAG) + .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) + .build()) + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.SIGNER_ID) + .setId(batchSpecificationMessage.getSignerId()) + .build()) + .build(); + + for (String db : meerkatDBs) { + + try { + SingleServerReadMessagesWorker messagesWorker = new SingleServerReadMessagesWorker(db, filterList, 0); + + List messages = messagesWorker.call(); + + if (messages == null || messages.size() < 1) + continue; + + BulletinBoardMessage batchMessage = messages.get(0); + + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(db, batchSpecificationMessage, 0); + + List batchDataList = batchWorker.call(); + + CompleteBatch result = new CompleteBatch(batchMessage, batchDataList); + + return result; + + } catch (Exception ignored) {} } return null; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java new file mode 100644 index 0000000..1eed944 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -0,0 +1,188 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.util.BulletinBoardUtils; + +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel on 13/04/2016. + * Simple, straightforward implementation of the {@link BulletinBoardSynchronizer} interface + */ +public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronizer { + + private DeletableSubscriptionBulletinBoardClient localClient; + private AsyncBulletinBoardClient remoteClient; + + private volatile SyncStatus syncStatus; + + private List> messageCountCallbacks; + private List> syncStatusCallbacks; + + private static final MessageFilterList EMPTY_FILTER = MessageFilterList.getDefaultInstance(); + private static final int SLEEP_INTERVAL = 10000; // 10 Seconds + + private class SyncCallback implements FutureCallback> { + + @Override + public void onSuccess(List result) { + + SyncStatus newStatus = SyncStatus.PENDING; + + if (result.size() == 0) { + newStatus = SyncStatus.SYNCHRONIZED; + } + + else{ // Upload messages + + for (BulletinBoardMessage message : result){ + + if (message.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)){ + + // This is a batch message: need to upload batch data as well as the message itself + ByteString signerId = message.getSig(0).getSignerId(); + long batchID = Long.parseLong(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); + + BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder().build(); + + localClient.readBatch(batchSpecificationMessage, null); + + } + else{ + + // This is a regular message: post it + try { + remoteClient.postMessage(message); + } catch (CommunicationException e) { + newStatus = SyncStatus.SERVER_ERROR; + } + + } + } + + } + + updateSyncStatus(newStatus); + + } + + @Override + public void onFailure(Throwable t) { + + updateSyncStatus(SyncStatus.SERVER_ERROR); + + } + + } + + public SimpleBulletinBoardSynchronizer() { + this.syncStatus = SyncStatus.STOPPED; + } + + private synchronized void updateSyncStatus(SyncStatus newStatus) { + + if (newStatus != syncStatus){ + + syncStatus = newStatus; + + for (FutureCallback callback : syncStatusCallbacks){ + if (callback != null) + callback.onSuccess(syncStatus); + } + + } + + } + + @Override + public void init(DeletableSubscriptionBulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient) { + + updateSyncStatus(SyncStatus.STOPPED); + + this.localClient = localClient; + this.remoteClient = remoteClient; + + messageCountCallbacks = new LinkedList<>(); + syncStatusCallbacks = new LinkedList<>(); + + } + + @Override + public SyncStatus getSyncStatus() { + return syncStatus; + } + + @Override + public void subscribeToSyncStatus(FutureCallback callback) { + syncStatusCallbacks.add(callback); + } + + @Override + public List getRemainingMessages() throws CommunicationException{ + return localClient.readMessages(EMPTY_FILTER); + } + + @Override + public void getRemainingMessages(FutureCallback> callback) { + localClient.readMessages(EMPTY_FILTER, callback); + } + + @Override + public long getRemainingMessagesCount() throws CommunicationException { + return localClient.readMessages(EMPTY_FILTER).size(); + } + + @Override + public void subscribeToRemainingMessagesCount(FutureCallback callback) { + messageCountCallbacks.add(callback); + } + + @Override + public void run() { + + if (syncStatus != SyncStatus.STOPPED) { + + updateSyncStatus(SyncStatus.PENDING); + SyncCallback callback = new SyncCallback(); + + while (syncStatus != SyncStatus.STOPPED) { + + try { + + do { + localClient.readMessages(EMPTY_FILTER, callback); + } while (syncStatus == SyncStatus.PENDING); + + synchronized (this) { + this.wait(SLEEP_INTERVAL); + } + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + } + + } + + @Override + public void nudge() { + synchronized (this) { + this.notify(); + } + } + + @Override + public void stop() { + + updateSyncStatus(SyncStatus.STOPPED); + + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index f12430d..0a43562 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -97,7 +97,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void onSuccess(T result) { - futureCallback.onSuccess(result); + if (futureCallback != null) + futureCallback.onSuccess(result); } @Override @@ -115,7 +116,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i scheduleWorker(worker, this); } else { // No more retries: notify caller about failure - futureCallback.onFailure(t); + if (futureCallback != null) + futureCallback.onFailure(t); } } @@ -150,7 +152,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } if (batchDataRemaining.decrementAndGet() == 0){ - callback.onSuccess(this.aggregatedResult.get()); + if (callback != null) + callback.onSuccess(this.aggregatedResult.get()); } } @@ -158,7 +161,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void onFailure(Throwable t) { // Notify caller about failure - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } @@ -195,26 +199,16 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i if (remainingQueries.decrementAndGet() == 0){ - String batchIdStr = BulletinBoardUtils.findTagWithPrefix(batchMessage, BulletinBoardConstants.BATCH_ID_TAG_PREFIX); - - if (batchIdStr == null){ - callback.onFailure(new CommunicationException("Server returned invalid message with no Batch ID tag")); - } - - BeginBatchMessage beginBatchMessage = - BeginBatchMessage.newBuilder() - .setSignerId(batchMessage.getSig(0).getSignerId()) - .setBatchId(Integer.parseInt(batchIdStr)) - .addAllTag(BulletinBoardUtils.removePrefixTags(batchMessage, Arrays.asList(prefixes))) - .build(); - callback.onSuccess(new CompleteBatch(beginBatchMessage, batchDataList, batchMessage.getSig(0))); + if (callback != null) + callback.onSuccess(new CompleteBatch(batchMessage, batchDataList)); } } protected void fail(Throwable t) { if (failed.compareAndSet(false, true)) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } @@ -289,7 +283,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void onSuccess(List result) { // Report new messages to user - callback.onSuccess(result); + if (callback != null) + callback.onSuccess(result); // Remove last filter from list (MIN_ENTRY one) filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); @@ -315,7 +310,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i fail(); // Notify caller about failure and terminate subscription - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } @@ -397,7 +393,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } @@ -425,7 +422,8 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void onFailure(Throwable t) { - callback.onFailure(t); + if (callback != null) + callback.onFailure(t); } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java index ca8ef84..9568255 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java @@ -29,6 +29,8 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber private AtomicBoolean isSyncInProgress; private Semaphore rescheduleSemaphore; + private AtomicBoolean stopped; + private static final Float[] BREAKPOINTS = {0.5f, 0.75f, 0.9f, 0.95f, 0.99f, 0.999f}; public ThreadedBulletinBoardSubscriber(Collection clients, BulletinBoardClient localClient) { @@ -44,6 +46,8 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber isSyncInProgress = new AtomicBoolean(false); rescheduleSemaphore = new Semaphore(1); + stopped = new AtomicBoolean(false); + } /** @@ -131,7 +135,8 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber //TODO: log - callback.onFailure(e); // Hard error: Cannot guarantee subscription safety + if (callback != null) + callback.onFailure(e); // Hard error: Cannot guarantee subscription safety } @@ -217,7 +222,8 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber public void onSuccess(List result) { // Propagate result to caller - callback.onSuccess(result); + if (callback != null) + callback.onSuccess(result); // Renew subscription @@ -249,7 +255,8 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber public void onSuccess(List result) { // Propagate result to caller - callback.onSuccess(result); + if (callback != null) + callback.onSuccess(result); } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index cebeb8e..6b2ef4f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -679,6 +679,30 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ } + @Override + public IntMsg getMessageCount(MessageFilterList filterList) throws CommunicationException { + + BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); + + // SQL length is roughly 50 characters per filter + 50 for the query itself + StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); + + // Check if Tag/Signature tables are required for filtering purposes + + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.COUNT_MESSAGES)); + + // Get conditions + + SQLAndParameters sqlAndParameters = getSQLFromFilters(filterList); + sqlBuilder.append(sqlAndParameters.sql); + + // Run query and stream the output using a MessageCallbackHandler + + List count = jdbcTemplate.query(sqlBuilder.toString(), sqlAndParameters.parameters, new LongMapper()); + return IntMsg.newBuilder().setValue(count.get(0).intValue()).build(); + + } + /** * This method returns a string representation of the tag associated with a batch ID @@ -713,23 +737,9 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ .build()) .build(); - // SQL length is roughly 50 characters per filter + 50 for the query itself - StringBuilder sqlBuilder = new StringBuilder(50 * (filterList.getFilterCount() + 1)); + int count = getMessageCount(filterList).getValue(); - // Check if Tag/Signature tables are required for filtering purposes - - sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.COUNT_MESSAGES)); - - // Get conditions - - SQLAndParameters sqlAndParameters = getSQLFromFilters(filterList); - sqlBuilder.append(sqlAndParameters.sql); - - // Run query and stream the output using a MessageCallbackHandler - - List count = jdbcTemplate.query(sqlBuilder.toString(), sqlAndParameters.parameters, new LongMapper()); - - return (count.size() > 0) && (count.get(0) > 0); + return count > 0; } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 7c0f7fa..74b5f2a 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -15,14 +15,12 @@ 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 @@ -99,6 +97,16 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL bulletinBoard.readMessages(filterList, out); } + @Path(COUNT_MESSAGES_PATH) + @POST + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) + @Override + public IntMsg getMessageCount(MessageFilterList filterList) throws CommunicationException { + init(); + return bulletinBoard.getMessageCount(filterList); + } + @Path(READ_MESSAGES_PATH) @POST diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 9d7d5b8..91e577d 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -42,7 +42,15 @@ public interface BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering) * @return the list of messages */ - List readMessages(MessageFilterList filterList); + List readMessages(MessageFilterList filterList) throws CommunicationException; + + /** + * Read a given batch message from the bulletin board + * @param batchSpecificationMessage contains the data required to specify a single batch instance + * @return the complete batch + * @throws CommunicationException + */ + CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException; /** * Create a SyncQuery to test against that corresponds with the current server state for a specific filter list diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java index 9ddee90..f2fb3a9 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardConstants.java @@ -10,6 +10,7 @@ public interface BulletinBoardConstants { public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; public static final String GENERATE_SYNC_QUERY_PATH = "/generatesyncquery"; public static final String READ_MESSAGES_PATH = "/readmessages"; + public static final String COUNT_MESSAGES_PATH = "/countmessages"; public static final String READ_BATCH_PATH = "/readbatch"; public static final String POST_MESSAGE_PATH = "/postmessage"; public static final String BEGIN_BATCH_PATH = "/beginbatch"; diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index e458dbc..e26c54a 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -32,13 +32,21 @@ public interface BulletinBoardServer{ public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException; /** - * Read all messages posted matching the given filter + * Read all posted messages matching the given filters * @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 out) throws CommunicationException; + /** + * Return the number of posted messages matching the given filters + * @param filterList count only messages that match the filters (empty list or null means no filtering) + * @return an IntMsg containing the number of messages that match the filter + * @throws CommunicationException on DB connection error + */ + public IntMsg getMessageCount(MessageFilterList filterList) throws CommunicationException; + /** * Informs server about a new batch message * @param message contains the required data about the new batch diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java index 4b07225..569d4ef 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java @@ -1,22 +1,84 @@ package meerkat.bulletinboard; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.*; + +import com.google.common.util.concurrent.FutureCallback; + +import java.util.List; + /** * Created by Arbel Deutsch Peled on 08-Mar-16. * This interface defines the behaviour of a bulletin board synchronizer * This is used to make sure that data in a specific instance of a bulletin board server is duplicated to a sufficient percentage of the other servers */ -public interface BulletinBoardSynchronizer extends Runnable{ +public interface BulletinBoardSynchronizer extends Runnable { + + public enum SyncStatus{ + SYNCHRONIZED, // No more messages to upload + PENDING, // Synchronizer is uploading data + SERVER_ERROR, // Synchronizer encountered an error while uploading + STOPPED // Stopped/Not started by user + } /** - * - * @param localClient is a client for the local DB instance - * @param remoteClient is a client for the remote DBs - * @param minRedundancy + * Initializes the synchronizer with the required data to function properly + * @param localClient is a client for the temporary local storage server which contains only data to be uploaded + * @param remoteClient is a client for the remote servers into which the data needs to be uploaded */ - public void init(BulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient, float minRedundancy); + public void init(DeletableSubscriptionBulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient); + /** + * Returns the current server synchronization status + * @return the current synchronization status + */ + public SyncStatus getSyncStatus(); + + /** + * Creates a subscription to sync status changes + * @param callback is the handler for any status changes + */ + public void subscribeToSyncStatus(FutureCallback callback); + + /** + * Returns the messages which have not yet been synchronized + * @return the list of messages remaining to be synchronized + */ + public List getRemainingMessages() throws CommunicationException; + + /** + * Asynchronously returns the messages which have not yet been synchronized + * @param callback is the handler for the list of messages + */ + public void getRemainingMessages(FutureCallback> callback); + + /** + * Returns the current number of unsynchronized messages + * @return the current synchronization status + */ + public long getRemainingMessagesCount() throws CommunicationException; + + /** + * Creates a subscription to changes in the number of unsynchronized messages + * @param callback is the handler for any status changes + */ + public void subscribeToRemainingMessagesCount(FutureCallback callback); + + /** + * Starts the synchronization + */ @Override public void run(); + /** + * Lets the Synchronizer know that there is new data to be uploaded + * This is used to reduce the latency between local data-writes and uploads to the remote servers + */ + public void nudge(); + + /** + * Stops the synchronization + */ + public void stop(); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java index 649fd8b..89ae80a 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/CompleteBatch.java @@ -3,8 +3,9 @@ package meerkat.bulletinboard; import com.google.protobuf.Timestamp; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.*; -import meerkat.util.BulletinBoardMessageComparator; +import meerkat.util.BulletinBoardUtils; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -49,6 +50,36 @@ public class CompleteBatch { this.timestamp = timestamp; } + /** + * Combines the actual Bulletin board representation of a batch into a CompleteBatch object + * @param batchMessage is the BulletinBoard message that specifies the batch + * @param batchDataList is the (ordered) list of batch data + */ + public CompleteBatch(BulletinBoardMessage batchMessage, List batchDataList) throws IllegalArgumentException{ + + final String[] PREFIXES = { + BulletinBoardConstants.BATCH_ID_TAG_PREFIX, + BulletinBoardConstants.BATCH_TAG}; + + String batchIdStr = BulletinBoardUtils.findTagWithPrefix(batchMessage, BulletinBoardConstants.BATCH_ID_TAG_PREFIX); + + if (batchIdStr == null){ + throw new IllegalArgumentException(""); + } + + this.beginBatchMessage = + BeginBatchMessage.newBuilder() + .setSignerId(batchMessage.getSig(0).getSignerId()) + .setBatchId(Integer.parseInt(batchIdStr)) + .addAllTag(BulletinBoardUtils.removePrefixTags(batchMessage, Arrays.asList(PREFIXES))) + .build(); + + this.batchDataList = batchDataList; + this.signature = batchMessage.getSig(0); + this.timestamp = batchMessage.getMsg().getTimestamp(); + + } + public BeginBatchMessage getBeginBatchMessage() { return beginBatchMessage; } From 4c33e923b20c4ff69fef136be1172fafbd0cf5c7 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Sat, 16 Apr 2016 19:50:09 +0300 Subject: [PATCH 050/106] Implemented Synchronizer and Cached Client Not tested yet --- .../CachedBulletinBoardClient.java | 23 +++++-- .../LocalBulletinBoardClient.java | 47 +++++++++------ .../SimpleBulletinBoardClient.java | 52 ++++++++++++++-- .../SimpleBulletinBoardSynchronizer.java | 60 +++++++++++++++---- .../SingleServerBulletinBoardClient.java | 15 ++--- .../bulletinboard/BulletinBoardClient.java | 8 +++ .../BulletinBoardMessageDeleter.java | 23 ++++++- 7 files changed, 177 insertions(+), 51 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index c8b26c7..ac61114 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -14,7 +14,8 @@ import java.util.List; * It provides asynchronous access to several remote servers, as well as a local cache * Read operations are performed on the local server * Batch reads are performed on the local server and, if they fail, also on the remote servers - * Write operations are performed first on the local server and then on the remotes + * Write operations are performed on the local server + * A Synchronizer is employed in order to keep the remote server up to date * After any read is carried out, a subscription is made for the specific query to make sure the local DB will be updated * The database also employs a synchronizer which makes sure local data is sent to the remote servers */ @@ -23,6 +24,9 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien private final AsyncBulletinBoardClient localClient; private AsyncBulletinBoardClient remoteClient; private BulletinBoardSubscriber subscriber; + private BulletinBoardSynchronizer synchronizer; + + private Thread syncThread; private class SubscriptionStoreCallback implements FutureCallback> { @@ -62,15 +66,21 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien * @param localClient is a Client for the local instance * @param remoteClient is a Client for the remote instance(s); Should have endless retries for post operations * @param subscriber is a subscription service to the remote instance(s) + * @param queue is a client for a local deletable server to be used as a queue for not-yet-uploaded messages */ public CachedBulletinBoardClient(AsyncBulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient, - BulletinBoardSubscriber subscriber) { + BulletinBoardSubscriber subscriber, + DeletableSubscriptionBulletinBoardClient queue) { this.localClient = localClient; this.remoteClient = remoteClient; this.subscriber = subscriber; + this.synchronizer = new SimpleBulletinBoardSynchronizer(); + synchronizer.init(queue, remoteClient); + syncThread = new Thread(synchronizer); + syncThread.start(); } @Override @@ -302,8 +312,12 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien @Override public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { - localClient.postMessage(msg); - return remoteClient.postMessage(msg); + return localClient.postMessage(msg); + } + + @Override + public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { + return localClient.postBatch(completeBatch); } @Override @@ -331,6 +345,7 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien public void close() { localClient.close(); remoteClient.close(); + synchronizer.stop(); } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index 30ae462..109d5ed 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -57,7 +57,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override - public Boolean call() throws Exception { + public Boolean call() throws CommunicationException { return server.postMessage(msg).getValue(); } @@ -83,25 +83,21 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override - public Boolean call() throws Exception { + public Boolean call() throws CommunicationException { - if (!server.beginBatch(completeBatch.getBeginBatchMessage()).getValue()) - return false; + server.beginBatch(completeBatch.getBeginBatchMessage()); + + BatchMessage.Builder builder = BatchMessage.newBuilder() + .setSignerId(completeBatch.getSignature().getSignerId()) + .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()); int i=0; for (BatchData data : completeBatch.getBatchDataList()){ - BatchMessage message = BatchMessage.newBuilder() - .setSignerId(completeBatch.getSignature().getSignerId()) - .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()) - .setSerialNum(i) - .setData(data) - .build(); - - if (!server.postBatchMessage(message).getValue()) - return false; + server.postBatchMessage(builder.setSerialNum(i).setData(data).build()); i++; + } return server.closeBatchMessage(completeBatch.getCloseBatchMessage()).getValue(); @@ -501,17 +497,22 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { - try { - MessagePoster poster = new MessagePoster(msg); poster.call(); digest.update(msg); return digest.digestAsMessageID(); - } catch (Exception e) { - return null; - } + } + + @Override + public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { + + CompleteBatchPoster poster = new CompleteBatchPoster(completeBatch); + poster.call(); + + digest.update(completeBatch); + return digest.digestAsMessageID(); } @@ -609,6 +610,16 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } + @Override + public boolean deleteMessage(MessageID msgID) throws CommunicationException { + return server.deleteMessage(msgID).getValue(); + } + + @Override + public boolean deleteMessage(long entryNum) throws CommunicationException { + return server.deleteMessage(entryNum).getValue(); + } + @Override public void close() { try { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 9f6eae7..28252ae 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -2,8 +2,7 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; -import meerkat.bulletinboard.workers.singleserver.SingleServerReadBatchWorker; -import meerkat.bulletinboard.workers.singleserver.SingleServerReadMessagesWorker; +import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; import meerkat.comm.MessageInputStream; import meerkat.crypto.Digest; @@ -38,7 +37,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ protected Client client; - protected Digest digest; + protected BatchDigest digest; /** * Stores database locations and initializes the web Client @@ -53,7 +52,8 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); - digest = new SHA256Digest(); + // Wrap the Digest into a BatchDigest + digest = new GenericBatchDigest(new SHA256Digest()); } @@ -92,6 +92,50 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); } + @Override + public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { + + int pos = 0; + ByteString signerID = completeBatch.getSignature().getSignerId(); + int batchID = completeBatch.getBeginBatchMessage().getBatchId(); + + // Post message to all databases + try { + for (String db : meerkatDBs) { + + SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(db, completeBatch.getBeginBatchMessage(), 0); + + beginBatchWorker.call(); + + BatchMessage.Builder builder = BatchMessage.newBuilder().setSignerId(signerID).setBatchId(batchID); + + for (BatchData batchData : completeBatch.getBatchDataList()) { + + SingleServerPostBatchWorker postBatchWorker = + new SingleServerPostBatchWorker( + db, + builder.setData(batchData).setSerialNum(pos).build(), + 0); + + postBatchWorker.call(); + + pos++; + + } + + SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(db, completeBatch.getCloseBatchMessage(), 0); + + closeBatchWorker.call(); + + } + } catch (Exception e) { // Occurs only when server replies with valid status but invalid data + throw new CommunicationException("Error accessing database: " + e.getMessage()); + } + + digest.update(completeBatch); + return digest.digestAsMessageID(); + } + /** * Access each database and search for a given message ID * Return the number of databases in which the message was found diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index 1eed944..d96864a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -26,6 +26,27 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private static final MessageFilterList EMPTY_FILTER = MessageFilterList.getDefaultInstance(); private static final int SLEEP_INTERVAL = 10000; // 10 Seconds + private class MessageDeleteCallback implements FutureCallback { + + private final long entryNum; + + public MessageDeleteCallback(long entryNum) { + this.entryNum = entryNum; + } + + @Override + public void onSuccess(Boolean result) { + // Success: delete from database + localClient.deleteMessage(entryNum, null); + } + + @Override + public void onFailure(Throwable t) { + // Ignore + } + + } + private class SyncCallback implements FutureCallback> { @Override @@ -41,27 +62,40 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize for (BulletinBoardMessage message : result){ - if (message.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)){ + try { - // This is a batch message: need to upload batch data as well as the message itself - ByteString signerId = message.getSig(0).getSignerId(); - long batchID = Long.parseLong(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); + if (message.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)) { - BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder().build(); + // This is a batch message: need to upload batch data as well as the message itself + ByteString signerID = message.getSig(0).getSignerId(); + int batchID = Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); - localClient.readBatch(batchSpecificationMessage, null); + BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder() + .setSignerId(signerID) + .setBatchId(batchID) + .setStartPosition(0) + .build(); - } - else{ - // This is a regular message: post it - try { + CompleteBatch completeBatch = localClient.readBatch(batchSpecificationMessage); + + remoteClient.postBatch(completeBatch); + + + } else { + + // This is a regular message: post it + remoteClient.postMessage(message); - } catch (CommunicationException e) { - newStatus = SyncStatus.SERVER_ERROR; + } + localClient.deleteMessage(message.getEntryNum()); + + } catch (CommunicationException e) { + updateSyncStatus(SyncStatus.SERVER_ERROR); } + } } @@ -144,7 +178,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize @Override public void run() { - if (syncStatus != SyncStatus.STOPPED) { + if (syncStatus == SyncStatus.STOPPED) { updateSyncStatus(SyncStatus.PENDING); SyncCallback callback = new SyncCallback(); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 0a43562..74a8162 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -34,8 +34,6 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private ListeningScheduledExecutorService executorService; - protected BatchDigest batchDigest; - private long lastServerErrorTime; private final long failDelayInMilliseconds; @@ -347,9 +345,6 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Perform usual setup super.init(clientParams); - // Wrap the Digest into a BatchDigest - batchDigest = new GenericBatchDigest(digest); - // Remove all but first DB address String dbAddress = meerkatDBs.get(0); meerkatDBs = new LinkedList<>(); @@ -367,9 +362,9 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i scheduleWorker(worker, new RetryCallback<>(worker, callback)); // Calculate the correct message ID and return it - batchDigest.reset(); - batchDigest.update(msg.getMsg()); - return batchDigest.digestAsMessageID(); + digest.reset(); + digest.update(msg.getMsg()); + return digest.digestAsMessageID(); } @@ -435,9 +430,9 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i new BeginBatchCallback(completeBatch, callback) ); - batchDigest.update(completeBatch); + digest.update(completeBatch); - return batchDigest.digestAsMessageID(); + return digest.digestAsMessageID(); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 91e577d..4fb526a 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -27,6 +27,14 @@ public interface BulletinBoardClient { */ MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException; + /** + * Perform an end-to-end post of a signed batch message + * @param completeBatch contains all the data of the batch including the meta-data and the signature + * @return a unique identifier for the batch message + * @throws CommunicationException + */ + public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException; + /** * Check how "safe" a given message is in a synchronous manner * @param id is the unique message identifier for retrieval diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java index 6025719..cf57975 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardMessageDeleter.java @@ -13,18 +13,37 @@ import meerkat.protobuf.BulletinBoardAPI.*; public interface BulletinBoardMessageDeleter { /** - * Deletes a message from a Bulletin Board Server + * Deletes a message from a Bulletin Board Server in a possibly asynchronous manner + * Logs this action * @param msgID is the ID of the message to delete * @param callback handles the result of the operation */ public void deleteMessage(MessageID msgID, FutureCallback callback); /** - * Deletes a message from the Bulletin Board + * Deletes a message from the Bulletin Board in a possibly asynchronous manner * Logs this action * @param entryNum is the serial entry number of the message to delete * @param callback handles the result of the operation */ public void deleteMessage(long entryNum, FutureCallback callback); + /** + * Deletes a message from a Bulletin Board Server in a synchronous manner + * Logs this action + * @param msgID is the ID of the message to delete + * @return TRUE if the message was deleted and FALSE if it did not exist on the server + * @throws CommunicationException when an error occurs + */ + public boolean deleteMessage(MessageID msgID) throws CommunicationException; + + /** + * Deletes a message from the Bulletin Board in a synchronous manner + * Logs this action + * @param entryNum is the serial entry number of the message to delete + * @return TRUE if the message was deleted and FALSE if it did not exist on the server + * @throws CommunicationException when an error occurs + */ + public boolean deleteMessage(long entryNum) throws CommunicationException; + } From e042779b151ee547adae3b1ebf330e4e29b12b9c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 4 May 2016 17:46:05 +0300 Subject: [PATCH 051/106] Initial code for the Voting Booth. Still missing components: 1. An implementation of the encryptor (currently program crashes when trying to encrypt the PlaintextBallot) 2. The output device implementation should change to a runnable thread (with commands queue as the ui) Also needs to add comments EVERYWHERE. --- .../voting/SystemConsoleOutputDevice.java | 56 --- .../main/java/meerkat/voting/VotingBooth.java | 40 -- .../controller/VotingBoothController.java | 61 +++ .../voting/controller/VotingBoothImpl.java | 363 ++++++++++++++++ .../callbacks/CastOrAuditCallback.java | 47 +++ .../callbacks/ChannelChoiceCallback.java | 43 ++ .../callbacks/ControllerCallback.java | 27 ++ .../controller/callbacks/HaltCallback.java | 32 ++ .../callbacks/NewVoterCallback.java | 32 ++ .../callbacks/OutputDeviceCallback.java | 29 ++ .../controller/callbacks/VotingCallback.java | 40 ++ .../callbacks/WaitForFinishCallback.java | 29 ++ .../controller/commands/AuditCommand.java | 10 + .../controller/commands/CastCommand.java | 10 + .../commands/ChannelChoiceCommand.java | 10 + .../commands/ChannelDeterminedCommand.java | 15 + .../commands/ControllerCommand.java | 19 + .../EncryptAndCommitBallotCommand.java | 12 + .../commands/RestartVotingCommand.java | 8 + .../controller/selector/QuestionSelector.java | 20 + .../selector/SimpleCategoriesData.java | 73 ++++ .../SimpleListCategoriesSelector.java | 121 ++++++ .../selector/SingleChosenAnswer.java | 31 ++ .../voting/encryptor/VBEncryptorImpl.java | 14 + .../{ => encryptor}/VotingBoothEncryptor.java | 12 +- .../{ => output}/BallotOutputDevice.java | 21 +- .../output/SystemConsoleOutputDevice.java | 98 +++++ .../voting/{ => storage}/StorageManager.java | 17 +- .../voting/storage/StorageManagerMockup.java | 67 +++ .../meerkat/voting/ui/SystemConsoleUI.java | 393 ++++++++++++++++++ .../meerkat/voting/ui/TickerTimerTask.java | 25 ++ .../voting/{ => ui}/VotingBoothUI.java | 15 +- .../ui/uicommands/CastOrAuditUICommand.java | 12 + .../ui/uicommands/ChannelChoiceUICommand.java | 22 + .../voting/ui/uicommands/HaltCommand.java | 22 + .../ui/uicommands/RaceVotingUICommand.java | 22 + .../ui/uicommands/StartSessionUICommand.java | 13 + .../voting/ui/uicommands/TickCommand.java | 14 + .../voting/ui/uicommands/UICommand.java | 16 + .../ui/uicommands/WaitForFinishCommand.java | 23 + 40 files changed, 1814 insertions(+), 120 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBooth.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java create mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java rename voting-booth/src/main/java/meerkat/voting/{ => encryptor}/VotingBoothEncryptor.java (79%) rename voting-booth/src/main/java/meerkat/voting/{ => output}/BallotOutputDevice.java (53%) create mode 100644 voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java rename voting-booth/src/main/java/meerkat/voting/{ => storage}/StorageManager.java (51%) create mode 100644 voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java rename voting-booth/src/main/java/meerkat/voting/{ => ui}/VotingBoothUI.java (83%) create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java diff --git a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java deleted file mode 100644 index 7546d53..0000000 --- a/voting-booth/src/main/java/meerkat/voting/SystemConsoleOutputDevice.java +++ /dev/null @@ -1,56 +0,0 @@ -package meerkat.voting; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 15/02/16. - */ -public class SystemConsoleOutputDevice implements BallotOutputDevice { - - /* - * Returns the UTF8 decoding of byte-string data - */ - private static String bytesToString(ByteString data) { - return data.toStringUtf8(); - } - - @Override - public void commitToBallot(long sessionId, EncryptedBallot encryptedBallot, VotingBooth.Callback callback) { - - System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " - + bytesToString(encryptedBallot.getData().getData())); - - callback.ballotCommitResult(sessionId, true); - - } - - @Override - public void audit(long sessionId, EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, VotingBooth.Callback callback) { - - //TODO: generate standard form for this - System.out.println("Ballot #" + encryptedBallot.getSerialNumber() + ": " - + bytesToString(encryptedBallot.getData().getData())); - - callback.ballotAuditResult(sessionId, true); - - } - - @Override - public void castBallot(long sessionId, VotingBooth.Callback callback) { - - System.out.println("Ballot finalized!"); - - callback.ballotCastResult(sessionId, true); - - } - - @Override - public void cancelBallot(long sessionId, VotingBooth.Callback callback) { - - System.out.println("Ballot cancelled!"); - - callback.ballotCancelResult(sessionId, true); - - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java b/voting-booth/src/main/java/meerkat/voting/VotingBooth.java deleted file mode 100644 index 9ef863c..0000000 --- a/voting-booth/src/main/java/meerkat/voting/VotingBooth.java +++ /dev/null @@ -1,40 +0,0 @@ -package meerkat.voting; - -import meerkat.protobuf.Voting.*; - -/** - * An interface for the controller component of the voting booth - */ -public interface VotingBooth { - - /** - * initialize using the BoothParams protobuf and sett all the different components of the Voting Booth to be recognized by this controller - * @param boothParams - * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection - * @param vbEncryptor the encryption module - * @param vbUI User interface in which the voter chooses his answers - * @param vbStorageManager storage component for handling files and USB sticks - */ - public void init (BoothParams boothParams, - BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, - VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * set the voting questions - * @param questions - */ - public void setBallotQuestions (BallotQuestion[] questions); - - /** - * a synchronous function. Starts running the controller component, and basically run the whole system for voting - */ - public void run (); - - /** - * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system - */ - public void shutDown(); - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java new file mode 100644 index 0000000..ee51f78 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -0,0 +1,61 @@ +package meerkat.voting.controller; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.ui.VotingBoothUI; +import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.output.BallotOutputDevice; +import meerkat.voting.storage.StorageManager; + +import java.util.ArrayList; + + +/** + * An interface for the controller component of the voting booth + */ +public interface VotingBoothController { + + /** + * initialize by setting all the different components of the Voting Booth to be recognized by this controller + * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection + * @param vbEncryptor the encryption module + * @param vbUI User interface in which the voter chooses his answers + * @param vbStorageManager storage component for handling files and USB sticks + */ + public void init (BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager); + + /** + * set the voting questions + * @param questions + */ + public void setBallotChannelChoiceQuestions(BallotQuestion[] questions); + public void setBallotChannelChoiceQuestions(ArrayList questions); + + /** + * Set the channel question-selector (the component which matches the ballot questions to each user) + * @param selector the question selector instance + */ + public void setChannelQuestionSelector (QuestionSelector selector); + + /** + * set the voting race questions + * @param questions + */ + public void setBallotRaceQuestions(BallotQuestion[] questions); + public void setBallotRaceQuestions(ArrayList questions); + + /** + * a synchronous function. Starts running the controller component, and basically run the whole system for voting + */ + public void run (); + + /** + * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system + */ + public void shutDown(); + + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java new file mode 100644 index 0000000..fd67cac --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -0,0 +1,363 @@ +package meerkat.voting.controller; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.*; +import meerkat.voting.controller.commands.*; +import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.output.BallotOutputDevice; +import meerkat.voting.storage.StorageManager; +import meerkat.voting.ui.VotingBoothUI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 28/03/16. + */ +public class VotingBoothImpl implements VotingBoothController, Runnable { + + private BallotOutputDevice outputDevice; + private VotingBoothEncryptor encryptor; + private VotingBoothUI ui; + private StorageManager storageManager; + private BallotQuestion[] questionsForChoosingChannel; + private BallotQuestion[] questions; + private QuestionSelector questionSelector; + + private LinkedBlockingQueue queue; + + private Logger logger; + + private ControllerState state; + private boolean shutDownHasBeenCalled; + + protected final int MAX_REQUEST_IDENTIFIER = 100000; + private static int requestCounter = 0; + + private UIElement waitForCommitMessage; + private UIElement waitForAuditMessage; + private UIElement waitForCastMessage; + + + + public VotingBoothImpl () { + logger = LoggerFactory.getLogger(VotingBoothImpl.class); + logger.info("A VotingBoothImpl is constructed"); + shutDownHasBeenCalled = false; + queue = new LinkedBlockingQueue<>(); + + waitForCommitMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build(); + waitForAuditMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build(); + waitForCastMessage = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build(); + + state = new VotingBoothImpl.ControllerState(); + + } + + @Override + public void init(BallotOutputDevice outputDevice, + VotingBoothEncryptor vbEncryptor, + VotingBoothUI vbUI, + StorageManager vbStorageManager) { + logger.info("init is called"); + this.outputDevice = outputDevice; + this.encryptor = vbEncryptor; + this.ui = vbUI; + this.storageManager = vbStorageManager; + } + + @Override + public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) { + logger.info("setting questions"); + this.questionsForChoosingChannel = questions; + } + + @Override + public void setBallotChannelChoiceQuestions(ArrayList questions) { + BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; + for (int i = 0; i < bqArr.length; ++i) { + bqArr[i] = questions.get(i); + } + setBallotChannelChoiceQuestions(bqArr); + } + + @Override + public void setChannelQuestionSelector(QuestionSelector selector) { + this.questionSelector = selector; + } + + @Override + public void setBallotRaceQuestions(BallotQuestion[] questions) { + logger.info("setting questions"); + this.questions = questions; + } + + @Override + public void setBallotRaceQuestions(ArrayList questions) { + // TODO: why does the toArray method not work?? + //BallotQuestion[] bqArr = (BallotQuestion[])(questions.toArray()); + BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; + for (int i = 0; i < bqArr.length; ++i) { + bqArr[i] = questions.get(i); + } + setBallotRaceQuestions(bqArr); + } + + @Override + public void run() { + logger.info("run command has been called"); + runVotingFlow(); + doShutDown(); + + } + + @Override + public void shutDown() { + logger.info("shutDown command has been called"); + synchronized (this) { + shutDownHasBeenCalled = true; + } + + } + + + + private void runVotingFlow () { + logger.info("entered the voting flow"); + + queue.add(new RestartVotingCommand(generateRequestIdentifier(), state.currentBallotSerialNumber)); + + while (! wasShutDownCalled()) { + try { + ControllerCommand task = queue.take(); + handleSingleTask (task); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from task queue " + e); + } + } + } + + private void doShutDown () { + logger.info("running shutDown"); + } + + private void handleSingleTask (ControllerCommand task) { + if (task instanceof RestartVotingCommand) { + doRestartVoting (); + return; + } + if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) { + String errorMessage = "handleSingleTask: received a task too old. " + + task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; + logger.warn (errorMessage); + return; + } + + if (task instanceof CastCommand) { + doCast(); + return; + } + else if (task instanceof AuditCommand) { + doAudit(); + return; + } + else if (task instanceof ChannelChoiceCommand) { + doChooseChannel(); + return; + } + else if (task instanceof ChannelDeterminedCommand) { + doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); + return; + } + else if (task instanceof EncryptAndCommitBallotCommand) { + doCommit ((EncryptAndCommitBallotCommand)task); + return; + } + else { + String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " + + task.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + /* + Map taskHandlers = new Map<>() { +CaskTask.getClass().getName() : doCast(), +ChannelChoiceCommand.getClass().getName() : doChooseChannel(), +} + + + + */ + + private synchronized boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + private void doRestartVoting () { + queue.clear(); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.NEW_VOTER; + state.currentBallotSerialNumber += 1; + + ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber , this.queue)); + } + + private void doChooseChannel () { + if (state.stateIdentifier == VBState.NEW_VOTER) { + logger.debug("doing chooseChannel"); + state.stateIdentifier = VBState.CHOOSE_CHANNEL; + ui.chooseChannel(this.questionsForChoosingChannel, + new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doChooseChannel: current state is " + state.stateIdentifier); + // ignore this request + } + } + + private void doSetChannelAndAskQuestions (ChannelDeterminedCommand task) { + if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { + logger.debug("doing set channel and ask questions"); + state.stateIdentifier = VBState.ANSWER_QUESTIONS; + BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers; + state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); + state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); + state.stateIdentifier = VBState.ANSWER_QUESTIONS; + ui.askVoterQuestions(state.channelSpecificQuestions, + new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + private void doCommit (EncryptAndCommitBallotCommand task) { + if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { + logger.debug("doing commit"); + state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; + VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); + state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + state.secrets = encryptionAndSecrets.getSecrets(); + ui.notifyVoterToWaitForFinish(waitForCommitMessage, + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); + outputDevice.commitToBallot(state.plaintextBallot, + state.encryptedBallot, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doCommit: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + private void doAudit () { + if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { + logger.debug("doing audit"); + state.stateIdentifier = VBState.FINALIZING; + outputDevice.audit(state.secrets, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(waitForAuditMessage, + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doAudit: current state is " + state.stateIdentifier); + // ignore this request + } + } + + private void doCast () { + if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { + logger.debug("casting ballot"); + state.stateIdentifier = VBState.FINALIZING; + outputDevice.castBallot( + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(waitForCastMessage, + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + logger.warn("doCast: current state is " + state.stateIdentifier); + // ignore this request + } + } + + + + + + private enum VBState { + NEW_VOTER, + CHOOSE_CHANNEL, + ANSWER_QUESTIONS, + COMMITTING_TO_BALLOT, + CAST_OR_AUDIT, + FINALIZING + } + + + private class ControllerState { + public VotingBoothImpl.VBState stateIdentifier; + public int channelIdentifier; + public BallotQuestion[] channelSpecificQuestions; + public PlaintextBallot plaintextBallot; + public EncryptedBallot encryptedBallot; + public BallotSecrets secrets; + public int lastRequestIdentifier; + public long currentBallotSerialNumber; + + public ControllerState () { + plaintextBallot = null; + encryptedBallot = null; + secrets = null; + lastRequestIdentifier = -1; + channelIdentifier = -1; + channelSpecificQuestions = null; + currentBallotSerialNumber = 0; + } + + + public void clearPlaintext () { + //TODO: Do we need safe erasure? + plaintextBallot = null; + } + + public void clearCiphertext () { + //TODO: Do we need safe erasure? + encryptedBallot = null; + secrets = null; + } + } + + + private int generateRequestIdentifier() { + ++requestCounter; + if (requestCounter >= MAX_REQUEST_IDENTIFIER) { + requestCounter = 1; + } + return requestCounter; + } + + +} + diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java new file mode 100644 index 0000000..0a5522f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -0,0 +1,47 @@ +package meerkat.voting.controller.callbacks; + + +import meerkat.voting.controller.commands.*; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.ui.VotingBoothUI.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class CastOrAuditCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); + + public CastOrAuditCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert (result instanceof FinalizeBallotChoice); + + if (result == FinalizeBallotChoice.CAST) { + controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else if (result == FinalizeBallotChoice.AUDIT) { + controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("CastOrAuditCallback got an unrecognized response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + } + + @Override + public void onFailure(Throwable t) { + logger.error("CastOrAuditCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} + + + diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java new file mode 100644 index 0000000..c6db8d4 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -0,0 +1,43 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.protobuf.Voting; +import meerkat.voting.controller.commands.ChannelDeterminedCommand; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelChoiceCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); + + public ChannelChoiceCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert (result instanceof Voting.BallotAnswer[]); + if (((Voting.BallotAnswer[])result).length != 0) { + logger.debug("callback for channel choice returned success"); + controllerQueue.add( + new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + } + else { + logger.debug("ChannelChoiceCallback got a cancellation response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("channel choice initiated a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java new file mode 100644 index 0000000..2c33cbc --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -0,0 +1,27 @@ +package meerkat.voting.controller.callbacks; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.voting.controller.commands.ControllerCommand; + +import java.util.concurrent.LinkedBlockingQueue; + +public abstract class ControllerCallback implements FutureCallback { + private final int requestIdentifier; + private final long ballotSerialNumber; + protected LinkedBlockingQueue controllerQueue; + + protected ControllerCallback (int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + this.requestIdentifier = requestId; + this.ballotSerialNumber = ballotSerialNumber; + this.controllerQueue = controllerQueue; + } + + protected int getRequestIdentifier () { + return requestIdentifier; + } + protected long getBallotSerialNumber () { + return ballotSerialNumber; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java new file mode 100644 index 0000000..c251a0f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java @@ -0,0 +1,32 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 21/04/16. + */ +public class HaltCallback extends ControllerCallback{ + protected final static Logger logger = LoggerFactory.getLogger(HaltCallback.class); + + public HaltCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + + @Override + public void onSuccess(Object result) { + throw new UnsupportedOperationException("HaltCallback: onSuccess: There cannot be a successful return for this task. Returned value is " + result); + } + + @Override + public void onFailure(Throwable t) { + logger.error("Halting initiated a failure: " + t); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java new file mode 100644 index 0000000..bdb53c3 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -0,0 +1,32 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ChannelChoiceCommand; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class NewVoterCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); + + public NewVoterCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + logger.debug("callback for new voting returned success"); + assert v==null; + controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("New voting session got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java new file mode 100644 index 0000000..81a14c4 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class OutputDeviceCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); + + public OutputDeviceCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + assert v instanceof Void; + } + + @Override + public void onFailure(Throwable t) { + logger.error("WaitForFinishCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java new file mode 100644 index 0000000..5e0cc1a --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -0,0 +1,40 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.protobuf.Voting; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class VotingCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); + + public VotingCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object result) { + assert result instanceof Voting.BallotAnswer[]; + if (((Voting.BallotAnswer[])result).length != 0) { + logger.debug("callback for voting returned success"); + controllerQueue.add( + new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + } + else { + logger.debug("VotingCallback got a cancellation response: " + result); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("voting initiated a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java new file mode 100644 index 0000000..d56327d --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class WaitForFinishCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); + + public WaitForFinishCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Object v) { + assert v instanceof Void; + } + + @Override + public void onFailure(Throwable t) { + logger.error("WaitForFinishCallback got a failure: " + t); + controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java new file mode 100644 index 0000000..d2c99f2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class AuditCommand extends ControllerCommand { + public AuditCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java new file mode 100644 index 0000000..0621efb --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class CastCommand extends ControllerCommand { + public CastCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java new file mode 100644 index 0000000..f555e4b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelChoiceCommand extends ControllerCommand { + public ChannelChoiceCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java new file mode 100644 index 0000000..8fefbe7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -0,0 +1,15 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting; + +/** + * Created by hai on 11/04/16. + */ +public class ChannelDeterminedCommand extends ControllerCommand { + public Voting.BallotAnswer[] channelChoiceAnswers; + + public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + super(requestIdentifier, ballotSerialNumber); + channelChoiceAnswers = answers; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java new file mode 100644 index 0000000..5bfc5c2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java @@ -0,0 +1,19 @@ +package meerkat.voting.controller.commands; + +public abstract class ControllerCommand { + protected final int requestIdentifier; + protected final long ballotSerialNumber; + + protected ControllerCommand(int requestIdentifier, long ballotSerialNumber) { + this.requestIdentifier = requestIdentifier; + this.ballotSerialNumber = ballotSerialNumber; + } + + public long getBallotSerialNumber () { + return this.ballotSerialNumber; + } + + public int getRequestIdentifier () { + return this.requestIdentifier; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java new file mode 100644 index 0000000..bad2ff7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -0,0 +1,12 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting; + +public class EncryptAndCommitBallotCommand extends ControllerCommand { + public Voting.BallotAnswer[] votingAnswers; + + public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + super(requestIdentifier, ballotSerialNumber); + votingAnswers = answers; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java new file mode 100644 index 0000000..57906d2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java @@ -0,0 +1,8 @@ +package meerkat.voting.controller.commands; + + +public class RestartVotingCommand extends ControllerCommand { + public RestartVotingCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java new file mode 100644 index 0000000..3fd2188 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -0,0 +1,20 @@ +package meerkat.voting.controller.selector; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 02/05/16. + */ +public abstract class QuestionSelector { + + protected Object selectionData; + protected BallotQuestion[] allBallotQuestions; + + public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { + this.selectionData = selectionData; + this.allBallotQuestions = allBallotQuestions; + } + + public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers); + public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers); +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java new file mode 100644 index 0000000..83ae516 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java @@ -0,0 +1,73 @@ +package meerkat.voting.controller.selector; + +import java.util.HashMap; +import java.lang.Math; + +/** + * Created by hai on 02/05/16. + */ +public class SimpleCategoriesData { + + private int[] sharedDefaults; + private HashMap questionsSelections; + private int maxQuestionNumber; + + public SimpleCategoriesData() { + sharedDefaults = new int[0]; + questionsSelections = new HashMap(); + maxQuestionNumber = -1; + } + + public void setSharedDefaults(int[] sharedDefaultsIndices) { + this.sharedDefaults = sharedDefaultsIndices; + maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices)); + } + + public int[] getSharedDefaults() { + return sharedDefaults; + } + + public void setItem(SingleChosenAnswer key, int[] questionIndices) { + questionsSelections.put(key, questionIndices); + maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices)); + } + + public int[] getItem(SingleChosenAnswer key) { + return questionsSelections.get(key); + } + + public int getMaxQuestionNumber() { + return maxQuestionNumber; + } + + + private static int maxInt(int[] arr) { + int m = -1; + for (int i: arr) { + m = Math.max(i , m); + } + return m; + } + + public String toString () { + String s = "SimpleCategoriesData:\n"; + s += "shared : " + arrayToString(sharedDefaults) + "\n"; + s += "map : \n"; + for (SingleChosenAnswer key : questionsSelections.keySet()) { + s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n"; + } + return s; + } + + private String arrayToString (int[] a) { + if (a.length == 0) { + return "[]"; + } + String s = "[" + a[0]; + for (int i = 1; i < a.length; ++i) { + s += ", " + a[i]; + } + return s + "]"; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java new file mode 100644 index 0000000..31911e6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -0,0 +1,121 @@ +package meerkat.voting.controller.selector; + +import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; + +/** + * Created by hai on 02/05/16. + */ +public class SimpleListCategoriesSelector extends QuestionSelector { + protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + private boolean[] isSelected; + + public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { + super(selectionData, allBallotQuestions); + initializeAttributes (allBallotQuestions); + } + + public SimpleListCategoriesSelector(Object selectionData, ArrayList allBallotQuestions) { + super(selectionData, null); + BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()]; + for (int i = 0; i < questionsArr.length; ++i) { + questionsArr[i] = allBallotQuestions.get(i); + } + initializeAttributes (questionsArr); + } + + private void initializeAttributes (BallotQuestion[] allBallotQuestions) { + assert selectionData instanceof SimpleCategoriesData; + this.allBallotQuestions = allBallotQuestions; + SimpleCategoriesData data = (SimpleCategoriesData) selectionData; + int maxQuestionNumber = data.getMaxQuestionNumber(); + int length = allBallotQuestions.length; + if (maxQuestionNumber >= length) { + String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + length + " questions totally"; + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + isSelected = new boolean[allBallotQuestions.length]; + } + + + @Override + public int getChannelIdentifier(BallotAnswer[] channelChoiceAnswers) { + return 0; + } + + @Override + public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + java.util.Arrays.fill(isSelected, false); + markSelected(data.getSharedDefaults()); + markSelectionsOfVoterChannelChoice (channelChoiceAnswers); + int[] questionIndices = extractSelectedIndices(); + BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length]; + for (int i = 0; i < questionIndices.length; ++i) { + selectedQuestions[i] = allBallotQuestions[questionIndices[i]]; + } + return selectedQuestions; + } + + private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + for (int q = 0; q < channelChoiceAnswers.length; ++q) { + BallotAnswer ballotAnswer = channelChoiceAnswers[q]; + assertAnswerLengthIsOne(ballotAnswer, q); + SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0)); + assertKeyInSelectionData(key); + markSelected(data.getItem(key)); + } + } + + private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { + if (ballotAnswer.getAnswerCount() != 1) { + String errorMessage = "SimpleListCategoriesSelector expects a single answer for every channel choice question\n"; + errorMessage += "Answer to question number " + (questionNumber+1) + " is"; + for (long i : ballotAnswer.getAnswerList()) { + errorMessage += " " + i; + } + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + } + + private void assertKeyInSelectionData(SingleChosenAnswer key) { + SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + int[] questionListToAdd = data.getItem(key); + if (null == questionListToAdd) { + String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + key.answerNumber + " for question number " + key.questionNumber; + logger.error(errorMessage); + throw new ValueException(errorMessage); + } + } + + private void markSelected (int[] questionIndices) { + for (int i: questionIndices) { + isSelected[i] = true; + } + } + + private int[] extractSelectedIndices() { + int nSelected = 0; + for (boolean b: isSelected) { + if (b) { + nSelected++; + } + } + int[] res = new int[nSelected]; + int currIndex = 0; + for (int questionNumber = 0; questionNumber < isSelected.length; ++questionNumber) { + if (isSelected[questionNumber]) { + res[currIndex] = questionNumber; + currIndex++; + } + } + return res; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java new file mode 100644 index 0000000..fad377b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java @@ -0,0 +1,31 @@ +package meerkat.voting.controller.selector; + +/** + * Created by hai on 02/05/16. + */ +public class SingleChosenAnswer { + public int questionNumber; + public long answerNumber; + + public SingleChosenAnswer(int questionNumber, long answerNumber) { + this.questionNumber = questionNumber; + this.answerNumber = answerNumber; + } + + public String toString() { + return "SingleChosenAnswer(" + questionNumber + ", " + answerNumber + ")"; + } + + public boolean equals (Object other) { + if (!(other instanceof SingleChosenAnswer)) { + return false; + } + SingleChosenAnswer o = (SingleChosenAnswer)other; + return (o.questionNumber == this.questionNumber) && (o.answerNumber == this.answerNumber); + } + + @Override + public int hashCode () { + return questionNumber*1000 + (int)answerNumber; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java new file mode 100644 index 0000000..51ffef0 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java @@ -0,0 +1,14 @@ +package meerkat.voting.encryptor; + +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 26/04/16. + */ +public class VBEncryptorImpl implements VotingBoothEncryptor { + + @Override + public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) { + throw new UnsupportedOperationException(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java similarity index 79% rename from voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java rename to voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java index cc9b7bc..e9a885f 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java @@ -1,6 +1,5 @@ -package meerkat.voting; +package meerkat.voting.encryptor; -import com.sun.org.apache.xml.internal.security.encryption.EncryptedType; import meerkat.protobuf.Voting.*; /** @@ -20,8 +19,13 @@ public interface VotingBoothEncryptor { this.secrets = secrets; } - public EncryptedBallot getEncryptedBallot () { return encryptedBallot; } - public BallotSecrets getSecrets() { return secrets; } + public EncryptedBallot getEncryptedBallot () { + return encryptedBallot; + } + + public BallotSecrets getSecrets() { + return secrets; + } } diff --git a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java similarity index 53% rename from voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java rename to voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 0199523..8d1f7f1 100644 --- a/voting-booth/src/main/java/meerkat/voting/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -1,4 +1,4 @@ -package meerkat.voting; +package meerkat.voting.output; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; @@ -12,28 +12,29 @@ public interface BallotOutputDevice { /** * Output the encrypted ballot. This is a commitment before voter chooses casting or auditing * @param encryptedBallot - the encrypted ballot to commit to - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void commitToBallot(EncryptedBallot encryptedBallot, FutureCallback callback); + public void commitToBallot(PlaintextBallot plaintextBallot, + EncryptedBallot encryptedBallot, + FutureCallback callback); /** * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. - * @param encryptedBallot - the encrypted ballot * @param ballotSecrets - the secrtes of the encryption - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void audit(EncryptedBallot encryptedBallot, BallotSecrets ballotSecrets, FutureCallback callback); + public void audit(BallotSecrets ballotSecrets, FutureCallback callback); /** * Voter chose 'cast'. Finalize the ballot for use in the polling station - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void castBallot(FutureCallback callback); + public void castBallot(FutureCallback callback); /** * Cancelling the current ballot. This clears the state of the OutputDevice if the implementation has any such state. - * @param callback - a callback object through which to return a success flag + * @param callback - a callback object which expects no return value */ - public void cancelBallot(FutureCallback callback); + public void cancelBallot(FutureCallback callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java new file mode 100644 index 0000000..e1556d6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -0,0 +1,98 @@ +package meerkat.voting.output; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A toy OutputDevice class + * outputs everything simply to the System console + */ +public class SystemConsoleOutputDevice implements BallotOutputDevice { + + private Logger logger; + + public SystemConsoleOutputDevice () { + logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); + logger.info("A SystemConsoleOutputDevice is constructed"); + } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + + @Override + public void commitToBallot(PlaintextBallot plaintextBallot, + EncryptedBallot encryptedBallot, + FutureCallback callback) { + logger.debug("entered method commitToBallot"); + long plaintextSerialNumber = plaintextBallot.getSerialNumber(); + System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + long encryptedSerialNumber = encryptedBallot.getSerialNumber(); + System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); + if (plaintextSerialNumber != encryptedSerialNumber) { + logger.error("plaintext and encryption serial numbers do not match!! plaintext# = " + + plaintextSerialNumber + ", ciphertext# = " + encryptedSerialNumber); + } + ByteString encryptedData = encryptedBallot.getData().getData(); + System.out.println(bytesToString(encryptedData)); + callback.onSuccess(null); + } + + @Override + public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { + logger.debug("entered method audit"); + System.out.println("Auditing"); + printPlaintextBallot (ballotSecrets.getPlaintextBallot()); + printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); + printRandomnessGenerationProof (ballotSecrets.getProof()); + callback.onSuccess(null); + } + + private void printPlaintextBallot (PlaintextBallot plaintextBallot) { + long plaintextSerialNumber = plaintextBallot.getSerialNumber(); + System.out.println("Plaintext serial number = " + plaintextSerialNumber); + + System.out.println("Answers = "); + for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) { + String printableAnswer = ""; + for (long n : ballotAnswer.getAnswerList()) { + printableAnswer += n + " "; + } + System.out.println(printableAnswer); + } + } + + private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) { + System.out.println("Encryption Randomness = "); + ByteString data = encryptionRandomness.getData(); + System.out.println(bytesToString(data)); + } + + private void printRandomnessGenerationProof (RandomnessGenerationProof proof) { + System.out.println("Proof of randomness generation:"); + ByteString data = proof.getData(); + System.out.println(bytesToString(data)); + } + + + @Override + public void castBallot(FutureCallback callback) { + logger.debug("entered method castBallot"); + System.out.println("Ballot finalized for casting!"); + callback.onSuccess(null); + } + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("entered method cancelBallot"); + System.out.println("Ballot cancelled!"); + callback.onSuccess(null); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java similarity index 51% rename from voting-booth/src/main/java/meerkat/voting/StorageManager.java rename to voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index 0fd18ca..9bf7764 100644 --- a/voting-booth/src/main/java/meerkat/voting/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -1,7 +1,9 @@ -package meerkat.voting; +package meerkat.voting.storage; import meerkat.protobuf.Voting.*; +import java.io.IOException; + /** * An interface for the storage component of the voting booth */ @@ -14,8 +16,17 @@ public interface StorageManager { public boolean isAdminHardwareKeyInserted(); /** - * load the election params from a file. + * load the election params from the storage. * @return the current election params + * @throws IOException */ - public ElectionParams readElectionParams (); + public ElectionParams readElectionParams () throws IOException; + + /** + * write the election parameters protobuf to the storage + * @param params ElectionParams protobuf to save + * @throws IOException + */ + public void writeElectionParams(ElectionParams params) throws IOException; + } diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java new file mode 100644 index 0000000..23c89cf --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -0,0 +1,67 @@ +package meerkat.voting.storage; + +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * A mockup for the StorageManager interface + * Currently keeps the ElectionParams in a file in the user's home-directory + */ +public class StorageManagerMockup implements StorageManager { + + private boolean adminHardwareKeyInserted; + private Logger logger; + private String electionParamFullFilename = "~/meerkat_election_params_tempfile.dat"; + + public StorageManagerMockup () { + logger = LoggerFactory.getLogger(StorageManagerMockup.class); + logger.info("A StorageManagerMockup is constructed"); + this.adminHardwareKeyInserted = false; + } + + @Override + public boolean isAdminHardwareKeyInserted() { + logger.info("Entered method isAdminHardwareKeyInserted"); + logger.warn("isAdminHardwareKeyInserted is not yet fully implemented. It does not check the file system. " + + "Rather it just returns a private boolean member"); + return adminHardwareKeyInserted; + } + + @Override + public ElectionParams readElectionParams() throws IOException { + logger.info("Entered method readElectionParams"); + ElectionParams params; + try { + FileInputStream inputStream = new FileInputStream(electionParamFullFilename); + params = ElectionParams.parseFrom(inputStream); + inputStream.close(); + logger.info ("Successfully read election parameter protobuf from a file"); + } + catch (IOException e) { + logger.error("Could not read from the election parameter file: '" + electionParamFullFilename + "'."); + throw e; + } + return params; + } + + @Override + public void writeElectionParams(ElectionParams params) throws IOException { + logger.info("Entered method writeElectionParams"); + try { + FileOutputStream output = new FileOutputStream(electionParamFullFilename); + params.writeTo(output); + output.close(); + logger.info ("Successfully wrote election parameter protobuf to a file"); + } + catch (IOException e) { + logger.error("Could not write to the election parameter file: '" + electionParamFullFilename + "'."); + throw e; + } + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java new file mode 100644 index 0000000..4b6486e --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -0,0 +1,393 @@ +package meerkat.voting.ui; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Date; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.concurrent.LinkedBlockingQueue; + +import meerkat.voting.controller.callbacks.*; +import meerkat.voting.ui.uicommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.System.in; + + +public class SystemConsoleUI implements VotingBoothUI, Runnable { + + private BufferedReader bufferedReader; + private LinkedBlockingQueue queue; + private final Logger logger; + private final int tickDurationInMillisec = 10; + private Date startWaitingTime; + + + public SystemConsoleUI() { + logger = LoggerFactory.getLogger(SystemConsoleUI.class); + logger.info("A VB UI console is constructed"); + queue = new LinkedBlockingQueue<>(); + bufferedReader = new BufferedReader(new InputStreamReader(in)); + + startWaitingTime = null; + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + } + + + public void run () { + logger.info("entered the voting flow"); + while (true) { + try { + UICommand task = queue.take(); + handleSingleTask (task); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from task queue " + e); + } + } + } + + + private void handleSingleTask (UICommand task) { + if (!(task instanceof TickCommand)) { + if (startWaitingTime != null) { + stopWaiting(); + } + } + + if (task instanceof StartSessionUICommand) { + doShowWelcomeScreen((StartSessionUICommand)task); + return; + } + else if (task instanceof ChannelChoiceUICommand) { + doAskChannelChoiceQuestions((ChannelChoiceUICommand)task); + return; + } + else if (task instanceof RaceVotingUICommand) { + doAskVotingQuestions((RaceVotingUICommand)task); + return; + } + else if (task instanceof CastOrAuditUICommand) { + doCastOrAudit ((CastOrAuditUICommand)task); + return; + } + else if (task instanceof HaltCommand) { + doHalt((HaltCommand)task); + return; + } + else if (task instanceof WaitForFinishCommand) { + doWaitForFinish((WaitForFinishCommand)task); + return; + } + else if (task instanceof TickCommand) { + doTick (); + return; + } + else { + String errorMessage = "handleSingleTask: unknown type of UICommand received: " + + task.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + + @Override + public void startNewVoterSession(FutureCallback callback) { + logger.debug("UI interface call to startNewVoterSession"); + queue.add(new StartSessionUICommand((ControllerCallback)callback)); + } + + private void doShowWelcomeScreen(StartSessionUICommand task) { + logger.debug("UI entered doShowWelcomeScreen"); + System.out.println("Welcome, new voter!"); + waitForEnter(null); + ControllerCallback callback = task.getCallback(); + assert (callback instanceof NewVoterCallback); + ((NewVoterCallback)callback).onSuccess(null); + } + + private void stopWaiting () { + System.out.println (); + startWaitingTime = null; + + } + private void waitForEnter(String message) { + if (message != null) { + System.out.println(message); + } + System.out.println("\nPress ENTER to proceed.\n"); + String t = null; + while (t == null) { + try { + t = readInputLine(); + } + catch (IOException e) { + String errorMessage = "waitForEnter: threw an IOException: " + e; + logger.error(errorMessage); + System.err.println(errorMessage); + } + } + } + + @Override + public void chooseChannel(BallotQuestion[] questions, FutureCallback callback) { + logger.debug("UI interface call to chooseChannel"); + ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + queue.add(task); + } + + private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) { + logger.debug("UI: doAskChannelChoiceQuestions"); + System.out.println("Showing questions for choosing channel:\n"); + try { + BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); + task.getCallback().onSuccess(answers); + } + catch (IOException e) { + String errorMessage = "Channel choice failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + task.getCallback().onFailure(e); + } + } + + @Override + public void askVoterQuestions(BallotQuestion[] questions, FutureCallback callback) { + logger.debug("UI interface call to chooseChannel"); + queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); + } + + private void doAskVotingQuestions (RaceVotingUICommand task) { + logger.debug("UI: doAskVotingQuestions"); + System.out.println("Showing questions for race voting:\n"); + try { + BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); + task.getCallback().onSuccess(answers); + } + catch (IOException e) { + String errorMessage = "Asking voting questions failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + task.getCallback().onFailure(e); + } + } + + @Override + public void castOrAudit(FutureCallback callback) { + logger.debug("UI interface call to castOrAudit"); + queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); + } + + private void doCastOrAudit(CastOrAuditUICommand task) { + logger.debug("UI entered doCastOrAudit"); + System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); + + FinalizeBallotChoice fChoice; + + try { + String s = readInputLine(); + if (s.equals("cast") || s.equals("c")) { + fChoice = FinalizeBallotChoice.CAST; + } + else if (s.equals("audit") || s.equals("a")) { + fChoice = FinalizeBallotChoice.AUDIT; + } + else { + throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'"); + } + ControllerCallback callback = task.getCallback(); + assert (callback instanceof CastOrAuditCallback); + ((CastOrAuditCallback)callback).onSuccess(fChoice); + } + catch (IllegalArgumentException|IOException e) { + String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e; + logger.error(errorMessage); + task.getCallback().onFailure(e); + } + } + + + @Override + public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { + logger.debug("UI interface call to notifyVoterToWaitForFinish"); + queue.add(new WaitForFinishCommand(message, (ControllerCallback)callback)); + } + + public void doWaitForFinish (WaitForFinishCommand task) { + logger.debug("UI entered doWaitForFinish"); + + startWaitingTime = new Date(); + + UIElement message = task.getMessage(); + String messageString; + if (message.getType() != UIElementDataType.TEXT) { + messageString = "Default message: encountered an error. System halting"; + } else { + messageString = bytesToString(message.getData()); + } + System.out.println(messageString); + System.out.print ("Waiting : ."); + } + + @Override + public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageAndHalt"); + queue.add(new HaltCommand(errorMessage, (ControllerCallback)callback)); + } + + private void doHalt (HaltCommand task) { + logger.debug("UI entered doHalt"); + + UIElement errorMessage = task.getErrorMessage(); + String errorMessageString; + if (errorMessage.getType() != UIElementDataType.TEXT) { + errorMessageString = "Default message: encountered an error. System halting"; + } else { + errorMessageString = bytesToString(errorMessage.getData()); + } + System.out.println(errorMessageString); + + while (true) { + try { + wait(); + } catch (InterruptedException e) { + logger.error("UI halt has been interrupted. Details: " + e); + ControllerCallback callback = task.getCallback(); + assert callback instanceof HaltCallback; + ((HaltCallback) callback).onFailure(e); + } + } + } + + + @Override + public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { + throw new UnsupportedOperationException(); + } + + private void doTick () { + if (startWaitingTime != null) { + System.out.print ("."); // still waiting + } + } + + private String readInputLine() throws IOException{ + String s; + try { + s = this.bufferedReader.readLine(); + if (null == s) { + throw new IOException(); + } + } catch (IOException e) { + String errorMessage = "readInputLine: some error with reading input from console. details: " + e; + logger.error(errorMessage); + throw new IOException(e); + } + return s; + } + + + private void assertQuestionsAreValid (BallotQuestion[] questions) { + for (int index = 0; index < questions.length; ++index) { + BallotQuestion question = questions[index]; + if (question.getIsMandatory()) { + String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory"; + logger.error(errorMessage); + throw new UnsupportedOperationException(errorMessage); + } + if (!isQuestionOnlyText(question)) { + String errorMessage = "askVoterQuestions: question number " + index + " is not only text"; + logger.error(errorMessage); + throw new UnsupportedOperationException(errorMessage); + } + } + } + + private BallotAnswer[] askVoterForAnswers(BallotQuestion[] questions) throws IOException { + + assertQuestionsAreValid (questions); + + BallotAnswer answers[] = new BallotAnswer[questions.length]; + int index = 0; + while (index < questions.length) { + BallotQuestion question = questions[index]; + System.out.println("Question number " + index); + showQuestionOnScreen(question); + + System.out.println("UI screen: Enter your answer. You can also type '(b)ack' or '(c)ancel' or '(s)kip"); + String s = readInputLine(); + + if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { + return null; + } + else if (s.equals("back") || s.equals("b")) { + --index; + } + else if (s.equals("skip") || s.equals("s")) { + answers[index] = translateStringAnswerToProtoBufMessageAnswer(""); + ++index; + } + else { + answers[index] = translateStringAnswerToProtoBufMessageAnswer(s); + ++index; + } + } + return answers; + } + + //show question on the screen for the voter + private void showQuestionOnScreen(BallotQuestion question) { + if (!isQuestionOnlyText(question)) { + System.err.println("debug: an element in question is not of TEXT type"); + throw new UnsupportedOperationException(); + } + + System.out.println("Question text: " + bytesToString(question.getQuestion().getData())); + System.out.println("Description: " + bytesToString(question.getDescription().getData())); + int answerIndex = 0; + for (UIElement answer : question.getAnswerList()) { + ++answerIndex; + System.out.println("Answer " + answerIndex + ": " + bytesToString(answer.getData())); + } + } + + private boolean isQuestionOnlyText (BallotQuestion question) { + boolean isText = true; + if (question.getQuestion().getType() != UIElementDataType.TEXT + || question.getDescription().getType() != UIElementDataType.TEXT) { + isText = false; + } + for (UIElement answer : question.getAnswerList()) { + if (answer.getType() != UIElementDataType.TEXT) { + isText = false; + } + } + return isText; + } + + + private BallotAnswer translateStringAnswerToProtoBufMessageAnswer(String s) { + BallotAnswer.Builder bab = BallotAnswer.newBuilder(); + StringTokenizer st = new StringTokenizer(s); + while (st.hasMoreTokens()) { + bab.addAnswer(Integer.parseInt(st.nextToken())); + } + return bab.build(); + } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java new file mode 100644 index 0000000..a293e5f --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -0,0 +1,25 @@ +package meerkat.voting.ui; + +import meerkat.voting.ui.uicommands.TickCommand; +import meerkat.voting.ui.uicommands.UICommand; + +import java.util.TimerTask; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by hai on 25/04/16. + */ +class TickerTimerTask extends TimerTask { + private LinkedBlockingQueue uiQueue; + public TickerTimerTask (LinkedBlockingQueue uiQueue) { + this.uiQueue = uiQueue; + } + + @Override + public void run() { + UICommand t = uiQueue.peek(); + if ((t != null) && !(t instanceof TickCommand)) { + uiQueue.add(new TickCommand(null)); + } + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java similarity index 83% rename from voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java rename to voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index c2ccfea..ae96f7b 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -1,30 +1,31 @@ -package meerkat.voting; +package meerkat.voting.ui; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; + /** * An interface for the user interface component of the voting booth */ public interface VotingBoothUI { - public static enum FinalizeBallotChoice { + public enum FinalizeBallotChoice { CAST, AUDIT } /** * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning - * @param callback - a boolean future callback to return success when done + * @param callback - a boolean future callback to return when done */ - public void startNewVoterSession (FutureCallback callback); + public void startNewVoterSession (FutureCallback callback); /** * Present a question to the voter to decide on his voting channel. - * @param question a question to determine the right voting channel for this voter - * @param callback that's where we store the channel for the current voter + * @param questions questions to determine the right voting channel for this voter + * @param callback that's where we store the answers to decide channel upon for the current voter */ - public void chooseChannel (BallotQuestion question, FutureCallback callback); + public void chooseChannel (BallotQuestion[] questions, FutureCallback callback); /** * Presents the set of questions to the voter. Collect all his responses. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java new file mode 100644 index 0000000..993f64b --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -0,0 +1,12 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 21/04/16. + */ +public class CastOrAuditUICommand extends UICommand { + public CastOrAuditUICommand(ControllerCallback callback) { + super(callback); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java new file mode 100644 index 0000000..22d2ff3 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class ChannelChoiceUICommand extends UICommand { + + private final BallotQuestion[] questions; + + public ChannelChoiceUICommand(BallotQuestion[] questions, ControllerCallback callback) + { + super(callback); + this.questions = questions; + } + + public BallotQuestion[] getQuestions () { + return this.questions; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java new file mode 100644 index 0000000..5213354 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class HaltCommand extends UICommand { + + private final UIElement errorMessage; + + public HaltCommand(UIElement errorMessage, ControllerCallback callback) + { + super(callback); + this.errorMessage = errorMessage; + } + + public UIElement getErrorMessage () { + return this.errorMessage; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java new file mode 100644 index 0000000..31d2706 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class RaceVotingUICommand extends UICommand { + + private final BallotQuestion[] questions; + + public RaceVotingUICommand(BallotQuestion[] questions, ControllerCallback callback) + { + super(callback); + this.questions = questions; + } + + public BallotQuestion[] getQuestions () { + return this.questions; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java new file mode 100644 index 0000000..f1bc146 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -0,0 +1,13 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class StartSessionUICommand extends UICommand { + + public StartSessionUICommand(ControllerCallback callback) { + super(callback); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java new file mode 100644 index 0000000..3192f4c --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ +public class TickCommand extends UICommand { + + public TickCommand(ControllerCallback callback) { + super(callback); + assert null == callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java new file mode 100644 index 0000000..b22fdef --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +//TODO: make this class generic +public abstract class UICommand { + protected final ControllerCallback callback; + + protected UICommand(ControllerCallback callback) { + this.callback = callback; + } + + public ControllerCallback getCallback () { + return this.callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java new file mode 100644 index 0000000..fe9b1cc --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java @@ -0,0 +1,23 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 18/04/16. + */ + +public class WaitForFinishCommand extends UICommand { + + private final UIElement message; + + public WaitForFinishCommand(UIElement message, ControllerCallback callback) + { + super(callback); + this.message = message; + } + + public UIElement getMessage () { + return this.message; + } +} From c04ed42dcaee9d5900978fdca9404b9de2fe2bf4 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 4 May 2016 17:52:01 +0300 Subject: [PATCH 052/106] possible future protobufs for handling category channel selection. Summary: The initial code for the voting booth. Some things are still missing: 1. comments EVERYWHERE 2. an implementation for the encryptor (program crashes when trying to encrypt PlaintexBallot) 3. the OutputDevice class should become a thread, (runnable with a queue of commands as the UI component) Test Plan: Currently only simply run it with another main class. Reviewers: arbel.peled Differential Revision: https://proj-cs.idc.ac.il/D3 --- meerkat-common/src/main/proto/meerkat/voting.proto | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 8b49ca9..8ece676 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -39,6 +39,17 @@ message BallotQuestion { } +message QuestionCluster { + UIElement cluster_description = 1; + repeated int32 question_index = 2; + +} + +message Channel { + UIElement channel_description = 1; + repeated int32 cluster_index = 2; + +} // An answer to a specific ballot question. // The answer is a vector of signed integers, From b934894bc52d5139d5a0ce460a9f489201fa43cf Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 5 May 2016 16:55:10 +0300 Subject: [PATCH 053/106] Created Polling Station Scanner interface Implemented Web App for the scanner Not tested --- .../PollingStationConstants.java | 15 ++++ .../pollingstation/PollingStationScanner.java | 29 ++++++++ .../main/proto/meerkat/pollingstation.proto | 15 ++++ polling-station/build.gradle | 9 +++ .../PollingStationWebScanner.java | 71 +++++++++++++++++++ .../src/main/webapp/META-INF/jetty-env.xml | 12 ++++ .../src/main/webapp/WEB-INF/web.xml | 20 ++++++ 7 files changed, 171 insertions(+) create mode 100644 meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java create mode 100644 meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java create mode 100644 meerkat-common/src/main/proto/meerkat/pollingstation.proto create mode 100644 polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java create mode 100644 polling-station/src/main/webapp/META-INF/jetty-env.xml create mode 100644 polling-station/src/main/webapp/WEB-INF/web.xml diff --git a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java new file mode 100644 index 0000000..643a73c --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java @@ -0,0 +1,15 @@ +package meerkat.pollingstation; + +/** + * Created by Arbel Deutsch Peled on 21-Dec-15. + */ +public interface PollingStationConstants { + + // Relative addresses for Scanner operations + + public static final String POLLING_STATION_WEB_SCANNER_PATH = "/scanner"; + public static final String POLLING_STATION_WEB_SCANNER_SCAN_PATH = "/scan"; + public static final String POLLING_STATION_WEB_SCANNER_ERROR_PATH = "/error"; + + +} diff --git a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java new file mode 100644 index 0000000..9bea5b5 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java @@ -0,0 +1,29 @@ +package meerkat.pollingstation; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.PollingStation.*; +/** + * Created by Arbel on 05/05/2016. + * An interface for the scanner used by the Polling Station Committee + */ +public interface PollingStationScanner { + + /** + * Subscribes to new scans + * @param scanCallback is the handler for scanned data + */ + public void subscribe(FutureCallback scanCallback); + + /** + * Sends a scan to all subscribers + * @param scannedData contains the scanned data + */ + public void newScan(ScannedData scannedData); + + /** + * Notifies subscribers about an error that occurred during scan + * @param errorMsg is the error that occurred + */ + public void reportScanError(ErrorMsg errorMsg); + +} \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/pollingstation.proto b/meerkat-common/src/main/proto/meerkat/pollingstation.proto new file mode 100644 index 0000000..0cdc658 --- /dev/null +++ b/meerkat-common/src/main/proto/meerkat/pollingstation.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package meerkat; + +option java_package = "meerkat.protobuf"; + +// Container for scanned data +message ScannedData { + bytes data = 1; +} + +// Container for error messages +message ErrorMsg { + string msg = 1; +} \ No newline at end of file diff --git a/polling-station/build.gradle b/polling-station/build.gradle index d510d26..036d2e8 100644 --- a/polling-station/build.gradle +++ b/polling-station/build.gradle @@ -2,8 +2,10 @@ 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' @@ -41,6 +43,13 @@ 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.+' + + // Servlets + compile 'javax.servlet:javax.servlet-api:3.0.+' // Logging compile 'org.slf4j:slf4j-api:1.7.7' diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java new file mode 100644 index 0000000..a3aefdd --- /dev/null +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java @@ -0,0 +1,71 @@ +package meerkat.pollingstation; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.PollingStation; +import static meerkat.rest.Constants.*; + +import javax.ws.rs.*; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +import static meerkat.pollingstation.PollingStationConstants.*; +import meerkat.protobuf.PollingStation.*; + +/** + * Created by Arbel on 05/05/2016. + */ +@Path(POLLING_STATION_WEB_SCANNER_PATH) +public class PollingStationWebScanner implements PollingStationScanner{ + + private final List> callbacks; + + public PollingStationWebScanner() { + callbacks = new LinkedList<>(); + } + + @Override + public void subscribe(FutureCallback scanCallback) { + callbacks.add(scanCallback); + } + + @Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH) + @POST + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) + @Override + public void newScan(ScannedData scannedData) { + + if (callbacks.size() <= 0) + throw new RuntimeException("No subscribers to forward scan to!"); + + for (FutureCallback callback : callbacks){ + callback.onSuccess(scannedData); + } + + } + + @Path(POLLING_STATION_WEB_SCANNER_ERROR_PATH) + @POST + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) + @Override + public void reportScanError(PollingStation.ErrorMsg errorMsg) { + + if (callbacks.size() <= 0) + throw new RuntimeException("No subscribers to forward error to!"); + + for (FutureCallback callback : callbacks){ + callback.onFailure(new IOException(errorMsg.getMsg())); + } + + } + + @Path("/test") + @GET + public String test(){ + return "test"; + } + + +} diff --git a/polling-station/src/main/webapp/META-INF/jetty-env.xml b/polling-station/src/main/webapp/META-INF/jetty-env.xml new file mode 100644 index 0000000..c4d368f --- /dev/null +++ b/polling-station/src/main/webapp/META-INF/jetty-env.xml @@ -0,0 +1,12 @@ + + + + + org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern + none + + + org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern + none + + \ No newline at end of file diff --git a/polling-station/src/main/webapp/WEB-INF/web.xml b/polling-station/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..0632b0d --- /dev/null +++ b/polling-station/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,20 @@ + + + Jersey Hello World + + org.glassfish.jersey.servlet.ServletContainer + + + jersey.config.server.provider.packages + meerkat + + 1 + + + Jersey Hello World + /* + + + meerkat.pollingstation.PollingStationWebScanner + + From 061dc69fbc09a4d3af0b4874bcafa58c7641d79f Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 5 May 2016 17:01:00 +0300 Subject: [PATCH 054/106] File rename --- .../proto/meerkat/{pollingstation.proto => PollingStation.proto} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename meerkat-common/src/main/proto/meerkat/{pollingstation.proto => PollingStation.proto} (100%) diff --git a/meerkat-common/src/main/proto/meerkat/pollingstation.proto b/meerkat-common/src/main/proto/meerkat/PollingStation.proto similarity index 100% rename from meerkat-common/src/main/proto/meerkat/pollingstation.proto rename to meerkat-common/src/main/proto/meerkat/PollingStation.proto From 94f3920e6db9443cb1950859ba7e1df2f4544fac Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 23 May 2016 14:43:01 +0300 Subject: [PATCH 055/106] Many fixes, some are still only in temporary phase, according to what Arbel told me to do so far. --- .../voting/controller/SystemMessages.java | 84 +++++++ .../controller/VotingBoothController.java | 16 +- .../voting/controller/VotingBoothImpl.java | 217 ++++++++---------- .../callbacks/CastOrAuditCallback.java | 20 +- .../callbacks/ChannelChoiceCallback.java | 24 +- .../callbacks/ControllerCallback.java | 14 +- .../ErrorMessageRestartCallback.java | 29 +++ .../controller/callbacks/HaltCallback.java | 32 --- .../callbacks/NewVoterCallback.java | 9 +- .../callbacks/OutputDeviceCallback.java | 11 +- .../controller/callbacks/VotingCallback.java | 21 +- .../callbacks/WaitForFinishCallback.java | 11 +- .../commands/ChannelDeterminedCommand.java | 7 +- .../EncryptAndCommitBallotCommand.java | 12 +- .../commands/ReportErrorCommand.java | 16 ++ .../controller/commands/ShutDownCommand.java | 10 + .../controller/selector/QuestionSelector.java | 16 +- .../controller/selector/SelectionData.java | 7 + .../selector/SimpleCategoriesData.java | 60 +++-- .../SimpleListCategoriesSelector.java | 108 +++++---- .../selector/SingleChosenAnswer.java | 31 --- .../meerkat/voting/ui/SystemConsoleUI.java | 168 +++++++------- .../java/meerkat/voting/ui/VotingBoothUI.java | 8 +- .../ui/uicommands/CastOrAuditUICommand.java | 2 +- .../ui/uicommands/ChannelChoiceUICommand.java | 10 +- .../ui/uicommands/FatalErrorUICommand.java | 28 +++ .../voting/ui/uicommands/HaltCommand.java | 22 -- .../ui/uicommands/RaceVotingUICommand.java | 10 +- .../ui/uicommands/StartSessionUICommand.java | 2 +- .../voting/ui/uicommands/TickCommand.java | 2 +- .../voting/ui/uicommands/UICommand.java | 2 +- ...mmand.java => WaitForFinishUICommand.java} | 6 +- 32 files changed, 571 insertions(+), 444 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java rename voting-booth/src/main/java/meerkat/voting/ui/uicommands/{WaitForFinishCommand.java => WaitForFinishUICommand.java} (60%) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java new file mode 100644 index 0000000..ee6b506 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java @@ -0,0 +1,84 @@ +package meerkat.voting.controller; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.Voting.*; + +/** + * Created by hai on 18/05/16. + */ +final public class SystemMessages { + + private SystemMessages() { + // This is a static class. No instantiation of this is needed. + } + + public static UIElement getWaitForCommitMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build(); + } + + public static UIElement getWaitForAuditMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build(); + } + + public static UIElement getWaitForCastMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build(); + } + + public static UIElement getFatalForceRestartMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Fatal error: Internal controller queue received unrecognized command. Force restarting the voting process.")) + .build(); + } + + public static UIElement getRestartVotingButton() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Restart voting")) + .build(); + } + + public static UIElement getUnrecognizedFinalizeResponseMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) + .build(); + } + + public static UIElement getUnsuccessfulChannelChoiceMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) + .build(); + } + + public static UIElement getOutputDeviceFailureMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) + .build(); + } + + public static UIElement getUnsuccessfulVotingMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) + .build(); + } + + public static UIElement getSomethingWrongMessage() { + return UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) + .build(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index ee51f78..057f13d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -8,12 +8,13 @@ import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import java.util.ArrayList; +import java.util.List; /** * An interface for the controller component of the voting booth */ -public interface VotingBoothController { +public interface VotingBoothController extends Runnable{ /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller @@ -31,8 +32,7 @@ public interface VotingBoothController { * set the voting questions * @param questions */ - public void setBallotChannelChoiceQuestions(BallotQuestion[] questions); - public void setBallotChannelChoiceQuestions(ArrayList questions); + public void setBallotChannelChoiceQuestions(List questions); /** * Set the channel question-selector (the component which matches the ballot questions to each user) @@ -44,18 +44,12 @@ public interface VotingBoothController { * set the voting race questions * @param questions */ - public void setBallotRaceQuestions(BallotQuestion[] questions); - public void setBallotRaceQuestions(ArrayList questions); - - /** - * a synchronous function. Starts running the controller component, and basically run the whole system for voting - */ - public void run (); + public void setBallotRaceQuestions(List questions); /** * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system */ - public void shutDown(); + public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index fd67cac..cd53f65 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -12,20 +12,20 @@ import meerkat.voting.ui.VotingBoothUI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; /** * Created by hai on 28/03/16. */ -public class VotingBoothImpl implements VotingBoothController, Runnable { +public class VotingBoothImpl implements VotingBoothController { private BallotOutputDevice outputDevice; private VotingBoothEncryptor encryptor; private VotingBoothUI ui; private StorageManager storageManager; - private BallotQuestion[] questionsForChoosingChannel; - private BallotQuestion[] questions; + private List questionsForChoosingChannel; + private List questions; private QuestionSelector questionSelector; private LinkedBlockingQueue queue; @@ -33,38 +33,18 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { private Logger logger; private ControllerState state; - private boolean shutDownHasBeenCalled; + private volatile boolean shutDownHasBeenCalled; protected final int MAX_REQUEST_IDENTIFIER = 100000; private static int requestCounter = 0; - private UIElement waitForCommitMessage; - private UIElement waitForAuditMessage; - private UIElement waitForCastMessage; - - public VotingBoothImpl () { logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); shutDownHasBeenCalled = false; queue = new LinkedBlockingQueue<>(); - - waitForCommitMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) - .build(); - waitForAuditMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) - .build(); - waitForCastMessage = UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) - .build(); - - state = new VotingBoothImpl.ControllerState(); - + state = new ControllerState(); } @Override @@ -80,42 +60,22 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } @Override - public void setBallotChannelChoiceQuestions(BallotQuestion[] questions) { + public void setBallotChannelChoiceQuestions(List questions) { logger.info("setting questions"); this.questionsForChoosingChannel = questions; } - @Override - public void setBallotChannelChoiceQuestions(ArrayList questions) { - BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; - for (int i = 0; i < bqArr.length; ++i) { - bqArr[i] = questions.get(i); - } - setBallotChannelChoiceQuestions(bqArr); - } - @Override public void setChannelQuestionSelector(QuestionSelector selector) { this.questionSelector = selector; } @Override - public void setBallotRaceQuestions(BallotQuestion[] questions) { + public void setBallotRaceQuestions(List questions) { logger.info("setting questions"); this.questions = questions; } - @Override - public void setBallotRaceQuestions(ArrayList questions) { - // TODO: why does the toArray method not work?? - //BallotQuestion[] bqArr = (BallotQuestion[])(questions.toArray()); - BallotQuestion[] bqArr = new BallotQuestion[questions.size()]; - for (int i = 0; i < bqArr.length; ++i) { - bqArr[i] = questions.get(i); - } - setBallotRaceQuestions(bqArr); - } - @Override public void run() { logger.info("run command has been called"); @@ -124,17 +84,6 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } - @Override - public void shutDown() { - logger.info("shutDown command has been called"); - synchronized (this) { - shutDownHasBeenCalled = true; - } - - } - - - private void runVotingFlow () { logger.info("entered the voting flow"); @@ -151,64 +100,70 @@ public class VotingBoothImpl implements VotingBoothController, Runnable { } } - private void doShutDown () { - logger.info("running shutDown"); + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + queue.add(new ShutDownCommand()); } private void handleSingleTask (ControllerCommand task) { - if (task instanceof RestartVotingCommand) { - doRestartVoting (); - return; - } - if (task.getBallotSerialNumber() != state.currentBallotSerialNumber) { + if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) { + // probably an old command relating to some old ballot serial number. Simply log it and ignore it. String errorMessage = "handleSingleTask: received a task too old. " + task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; - logger.warn (errorMessage); + logger.debug(errorMessage); return; } - if (task instanceof CastCommand) { - doCast(); - return; + if (task instanceof RestartVotingCommand) { + doRestartVoting (); + } + else if (task instanceof CastCommand) { + doFinalize(false); } else if (task instanceof AuditCommand) { - doAudit(); - return; + doFinalize(true); } else if (task instanceof ChannelChoiceCommand) { doChooseChannel(); - return; } else if (task instanceof ChannelDeterminedCommand) { doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); - return; } else if (task instanceof EncryptAndCommitBallotCommand) { doCommit ((EncryptAndCommitBallotCommand)task); - return; + } + else if (task instanceof ReportErrorCommand) { + doReportErrorAndForceRestart((ReportErrorCommand)task); + } + else if (task instanceof ShutDownCommand) { + // wasShutDownCalled is now true. Do nothing. + // The program will not access the command queue anymore, and will exit normally + if (!wasShutDownCalled()) { + logger.warn("Received a ShutDownCommand command. At this point shutDownHasBeenCalled flag should have been True, but it's not..."); + shutDownHasBeenCalled = true; + } } else { - String errorMessage = "handleSingleTask: unknown type of ControllerCommand received: " + - task.getClass().getName(); - logger.error(errorMessage); - throw new RuntimeException(errorMessage); + logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); + doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); } } - /* - Map taskHandlers = new Map<>() { -CaskTask.getClass().getName() : doCast(), -ChannelChoiceCommand.getClass().getName() : doChooseChannel(), -} - - - - */ - - private synchronized boolean wasShutDownCalled () { + private boolean wasShutDownCalled () { return shutDownHasBeenCalled; } + private void doShutDown () { + logger.info("running callShutDown"); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.SHUT_DOWN; + //TODO: add commands to actually shut down the machine + } + private void doRestartVoting () { queue.clear(); state.clearPlaintext(); @@ -216,7 +171,22 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), state.stateIdentifier = VBState.NEW_VOTER; state.currentBallotSerialNumber += 1; - ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber , this.queue)); + ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + + private void doReportErrorAndForceRestart(ReportErrorCommand task) { + doReportErrorAndForceRestart(task.getErrorMessage()); + } + + private void doReportErrorAndForceRestart(UIElement errorMessage) { + queue.clear(); + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = VBState.FATAL_ERROR_FORCE_NEW_VOTER; + state.currentBallotSerialNumber += 1; + ui.showErrorMessageWithButtons(errorMessage, + new UIElement[]{SystemMessages.getRestartVotingButton()}, + new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } private void doChooseChannel () { @@ -227,7 +197,7 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doChooseChannel: current state is " + state.stateIdentifier); + logger.debug("doChooseChannel: current state is " + state.stateIdentifier); // ignore this request } } @@ -236,15 +206,14 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { logger.debug("doing set channel and ask questions"); state.stateIdentifier = VBState.ANSWER_QUESTIONS; - BallotAnswer[] channelChoiceAnswers = task.channelChoiceAnswers; + List channelChoiceAnswers = task.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); - state.stateIdentifier = VBState.ANSWER_QUESTIONS; ui.askVoterQuestions(state.channelSpecificQuestions, new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); + logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); // ignore this request } } @@ -254,10 +223,8 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; - VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); - state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); - state.secrets = encryptionAndSecrets.getSecrets(); - ui.notifyVoterToWaitForFinish(waitForCommitMessage, + setBallotData (task); + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); @@ -266,38 +233,38 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { - logger.warn("doCommit: current state is " + state.stateIdentifier); + logger.debug("doCommit: current state is " + state.stateIdentifier); // ignore this request } } - - private void doAudit () { - if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { - logger.debug("doing audit"); - state.stateIdentifier = VBState.FINALIZING; - outputDevice.audit(state.secrets, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - ui.notifyVoterToWaitForFinish(waitForAuditMessage, - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - } - else { - logger.warn("doAudit: current state is " + state.stateIdentifier); - // ignore this request - } + private void setBallotData (EncryptAndCommitBallotCommand task) { + state.plaintextBallot = PlaintextBallot.newBuilder() + .setSerialNumber(task.getBallotSerialNumber()) + .addAllAnswers(task.getVotingAnswers()) + .build(); + VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); + state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + state.secrets = encryptionAndSecrets.getSecrets(); } - private void doCast () { + private void doFinalize (boolean auditRequested) { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { - logger.debug("casting ballot"); + logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; - outputDevice.castBallot( - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); - ui.notifyVoterToWaitForFinish(waitForCastMessage, + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + if (auditRequested) { + outputDevice.audit(state.secrets, + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } + else { + outputDevice.castBallot( + new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + } } else { - logger.warn("doCast: current state is " + state.stateIdentifier); + logger.debug("doFinalize: current state is " + state.stateIdentifier); // ignore this request } } @@ -312,14 +279,16 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), ANSWER_QUESTIONS, COMMITTING_TO_BALLOT, CAST_OR_AUDIT, - FINALIZING + FINALIZING, + FATAL_ERROR_FORCE_NEW_VOTER, + SHUT_DOWN } private class ControllerState { - public VotingBoothImpl.VBState stateIdentifier; + public VBState stateIdentifier; public int channelIdentifier; - public BallotQuestion[] channelSpecificQuestions; + public List channelSpecificQuestions; public PlaintextBallot plaintextBallot; public EncryptedBallot encryptedBallot; public BallotSecrets secrets; @@ -338,12 +307,10 @@ ChannelChoiceCommand.getClass().getName() : doChooseChannel(), public void clearPlaintext () { - //TODO: Do we need safe erasure? plaintextBallot = null; } public void clearCiphertext () { - //TODO: Do we need safe erasure? encryptedBallot = null; secrets = null; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 0a5522f..69d5123 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; - +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.RestartVotingCommand; @@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class CastOrAuditCallback extends ControllerCallback { +public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); public CastOrAuditCallback(int requestId, @@ -20,18 +20,18 @@ public class CastOrAuditCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert (result instanceof FinalizeBallotChoice); - + public void onSuccess(FinalizeBallotChoice result) { if (result == FinalizeBallotChoice.CAST) { - controllerQueue.add(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new CastCommand(getRequestIdentifier(), getBallotSerialNumber())); } else if (result == FinalizeBallotChoice.AUDIT) { - controllerQueue.add(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new AuditCommand(getRequestIdentifier(), getBallotSerialNumber())); } else { logger.error("CastOrAuditCallback got an unrecognized response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnrecognizedFinalizeResponseMessage())); } } @@ -39,7 +39,9 @@ public class CastOrAuditCallback extends ControllerCallback { @Override public void onFailure(Throwable t) { logger.error("CastOrAuditCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnrecognizedFinalizeResponseMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index c6db8d4..f6abd5c 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -1,18 +1,18 @@ package meerkat.voting.controller.callbacks; -import meerkat.protobuf.Voting; -import meerkat.voting.controller.commands.ChannelDeterminedCommand; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.SystemMessages; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; /** * Created by hai on 11/04/16. */ -public class ChannelChoiceCallback extends ControllerCallback { +public class ChannelChoiceCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); public ChannelChoiceCallback(int requestId, @@ -22,22 +22,22 @@ public class ChannelChoiceCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert (result instanceof Voting.BallotAnswer[]); - if (((Voting.BallotAnswer[])result).length != 0) { + public void onSuccess(List result) { + if (result.size() != 0) { logger.debug("callback for channel choice returned success"); - controllerQueue.add( - new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } else { logger.debug("ChannelChoiceCallback got a cancellation response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } @Override public void onFailure(Throwable t) { logger.error("channel choice initiated a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulChannelChoiceMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java index 2c33cbc..d5684d2 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -1,14 +1,18 @@ package meerkat.voting.controller.callbacks; +/** + * Created by hai on 18/05/16. + */ import com.google.common.util.concurrent.FutureCallback; import meerkat.voting.controller.commands.ControllerCommand; import java.util.concurrent.LinkedBlockingQueue; -public abstract class ControllerCallback implements FutureCallback { +public abstract class ControllerCallback implements FutureCallback { + private final int requestIdentifier; private final long ballotSerialNumber; - protected LinkedBlockingQueue controllerQueue; + private LinkedBlockingQueue controllerQueue; protected ControllerCallback (int requestId, long ballotSerialNumber, @@ -21,7 +25,13 @@ public abstract class ControllerCallback implements FutureCallback { protected int getRequestIdentifier () { return requestIdentifier; } + protected long getBallotSerialNumber () { return ballotSerialNumber; } + + protected void enqueueCommand (ControllerCommand command) { + controllerQueue.add(command); + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java new file mode 100644 index 0000000..34f1194 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -0,0 +1,29 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class ErrorMessageRestartCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(ErrorMessageRestartCallback.class); + + public ErrorMessageRestartCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Integer result) { + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("Error message execution initiated a failure: " + t); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java deleted file mode 100644 index c251a0f..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/HaltCallback.java +++ /dev/null @@ -1,32 +0,0 @@ -package meerkat.voting.controller.callbacks; - -import meerkat.voting.controller.commands.ControllerCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Created by hai on 21/04/16. - */ -public class HaltCallback extends ControllerCallback{ - protected final static Logger logger = LoggerFactory.getLogger(HaltCallback.class); - - public HaltCallback(int requestId, - long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { - super(requestId, ballotSerialNumber, controllerQueue); - } - - - @Override - public void onSuccess(Object result) { - throw new UnsupportedOperationException("HaltCallback: onSuccess: There cannot be a successful return for this task. Returned value is " + result); - } - - @Override - public void onFailure(Throwable t) { - logger.error("Halting initiated a failure: " + t); - } - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java index bdb53c3..9b4e365 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class NewVoterCallback extends ControllerCallback { +public class NewVoterCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); public NewVoterCallback(int requestId, @@ -18,15 +18,14 @@ public class NewVoterCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { + public void onSuccess(Void v) { logger.debug("callback for new voting returned success"); - assert v==null; - controllerQueue.add(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ChannelChoiceCommand(getRequestIdentifier(), getBallotSerialNumber())); } @Override public void onFailure(Throwable t) { logger.error("New voting session got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java index 81a14c4..2432f49 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java @@ -1,13 +1,15 @@ package meerkat.voting.controller.callbacks; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class OutputDeviceCallback extends ControllerCallback { +public class OutputDeviceCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); public OutputDeviceCallback(int requestId, @@ -17,13 +19,14 @@ public class OutputDeviceCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { - assert v instanceof Void; + public void onSuccess(Void v) { } @Override public void onFailure(Throwable t) { logger.error("WaitForFinishCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getOutputDeviceFailureMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 5e0cc1a..5317374 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,15 +1,18 @@ package meerkat.voting.controller.callbacks; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; -public class VotingCallback extends ControllerCallback { +public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); public VotingCallback(int requestId, @@ -19,22 +22,22 @@ public class VotingCallback extends ControllerCallback { } @Override - public void onSuccess(Object result) { - assert result instanceof Voting.BallotAnswer[]; - if (((Voting.BallotAnswer[])result).length != 0) { + public void onSuccess(List result) { + if (result.size() != 0) { logger.debug("callback for voting returned success"); - controllerQueue.add( - new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), (Voting.BallotAnswer[]) result)); + enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } else { logger.debug("VotingCallback got a cancellation response: " + result); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } } @Override public void onFailure(Throwable t) { logger.error("voting initiated a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulVotingMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index d56327d..9f7a159 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,13 +1,15 @@ package meerkat.voting.controller.callbacks; +import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class WaitForFinishCallback extends ControllerCallback { +public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); public WaitForFinishCallback(int requestId, @@ -17,13 +19,14 @@ public class WaitForFinishCallback extends ControllerCallback { } @Override - public void onSuccess(Object v) { - assert v instanceof Void; + public void onSuccess(Void v) { } @Override public void onFailure(Throwable t) { logger.error("WaitForFinishCallback got a failure: " + t); - controllerQueue.add(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getSomethingWrongMessage())); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java index 8fefbe7..47d6f8b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -1,14 +1,15 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; +import java.util.List; /** * Created by hai on 11/04/16. */ public class ChannelDeterminedCommand extends ControllerCommand { - public Voting.BallotAnswer[] channelChoiceAnswers; + public List channelChoiceAnswers; - public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + public ChannelDeterminedCommand(int requestIdentifier, long ballotSerialNumber, List answers) { super(requestIdentifier, ballotSerialNumber); channelChoiceAnswers = answers; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index bad2ff7..074216f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -1,12 +1,18 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting; +import meerkat.protobuf.Voting.*; + +import java.util.List; public class EncryptAndCommitBallotCommand extends ControllerCommand { - public Voting.BallotAnswer[] votingAnswers; + private final List votingAnswers; - public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, Voting.BallotAnswer[] answers) { + public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, List answers) { super(requestIdentifier, ballotSerialNumber); votingAnswers = answers; } + + public List getVotingAnswers() { + return votingAnswers; + } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java new file mode 100644 index 0000000..b4a1fe7 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.controller.commands; + +import meerkat.protobuf.Voting.*; + +public class ReportErrorCommand extends ControllerCommand { + private final UIElement errorMessage; + + public ReportErrorCommand(int requestIdentifier, long ballotSerialNumber, UIElement errorMessage) { + super(requestIdentifier, ballotSerialNumber); + this.errorMessage = errorMessage; + } + + public UIElement getErrorMessage() { + return errorMessage; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java new file mode 100644 index 0000000..ee3c0f2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ShutDownCommand extends ControllerCommand { + public ShutDownCommand() { + super(0, 0); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index 3fd2188..e409e36 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -1,20 +1,18 @@ package meerkat.voting.controller.selector; import meerkat.protobuf.Voting.*; +import java.util.List; /** * Created by hai on 02/05/16. */ -public abstract class QuestionSelector { +public interface QuestionSelector { - protected Object selectionData; - protected BallotQuestion[] allBallotQuestions; + public void setAllBallotQuestions (List allBallotQuestions); - public QuestionSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { - this.selectionData = selectionData; - this.allBallotQuestions = allBallotQuestions; - } + public void setSelectionData(SelectionData data); - public abstract int getChannelIdentifier (BallotAnswer[] channelChoiceAnswers); - public abstract BallotQuestion[] selectQuestionsForVoter (BallotAnswer[] channelChoiceAnswers); + public int getChannelIdentifier (List channelChoiceAnswers); + + public List selectQuestionsForVoter (List channelChoiceAnswers); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java new file mode 100644 index 0000000..24a1125 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java @@ -0,0 +1,7 @@ +package meerkat.voting.controller.selector; + +/** + * Created by hai on 11/05/16. + */ +public class SelectionData { +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java index 83ae516..544a86d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java @@ -1,39 +1,60 @@ package meerkat.voting.controller.selector; -import java.util.HashMap; -import java.lang.Math; - /** - * Created by hai on 02/05/16. + * This class is the SelectionData used to initialize a SimpleListCategoriesSelector. + * It holds a table of question categories. + * Every answer in the channel choice phase dictates a category of questions to include in the ballot. + * This class is simply only the data class of these categories. + * Specifically the questionSelectionsByAnswer member is this categories table: + * questionSelectionsByAnswer[questionNumber][answerNumber] is an array of question indices to include in ballot + * whenever the voter answered answerNumber on question questionNumber in the channel choice phase. + * Also the sharedDefaults member is a category of question indices to include for EVERY voter, + * regardless of his channel choice answers */ -public class SimpleCategoriesData { +public class SimpleCategoriesData extends SelectionData{ - private int[] sharedDefaults; - private HashMap questionsSelections; + private int[] sharedDefaults; // a category of questions to include for every voter + // the categories + // first index is the question number, the second is the answer number. the value is an array of question indices in this category + private int[][][] questionSelectionsByAnswer; private int maxQuestionNumber; public SimpleCategoriesData() { sharedDefaults = new int[0]; - questionsSelections = new HashMap(); + questionSelectionsByAnswer = new int[0][][]; maxQuestionNumber = -1; } public void setSharedDefaults(int[] sharedDefaultsIndices) { - this.sharedDefaults = sharedDefaultsIndices; - maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(sharedDefaultsIndices)); + this.sharedDefaults = sharedDefaultsIndices.clone(); + maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices)); } public int[] getSharedDefaults() { return sharedDefaults; } - public void setItem(SingleChosenAnswer key, int[] questionIndices) { - questionsSelections.put(key, questionIndices); - maxQuestionNumber = Math.max(maxQuestionNumber, maxInt(questionIndices)); + public void setItem(int questionNumber, int answerNumber, int[] questionIndices) { + if (questionNumber >= questionSelectionsByAnswer.length) { + int[][][] tmp = new int[questionNumber+1][][]; + System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length); + tmp[questionNumber] = new int[0][]; + questionSelectionsByAnswer = tmp; + } + + if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) { + int[][] tmp = new int[answerNumber+1][]; + System.arraycopy(questionSelectionsByAnswer[questionNumber], 0, + tmp, 0, questionSelectionsByAnswer[questionNumber].length); + questionSelectionsByAnswer[questionNumber] = tmp; + } + + questionSelectionsByAnswer[questionNumber][answerNumber] = questionIndices.clone(); + maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(questionIndices)); } - public int[] getItem(SingleChosenAnswer key) { - return questionsSelections.get(key); + public int[] getItem(int questionNumber, int answerNumber) { + return questionSelectionsByAnswer[questionNumber][answerNumber]; } public int getMaxQuestionNumber() { @@ -41,7 +62,7 @@ public class SimpleCategoriesData { } - private static int maxInt(int[] arr) { + private static int maxIntInArray(int[] arr) { int m = -1; for (int i: arr) { m = Math.max(i , m); @@ -53,8 +74,11 @@ public class SimpleCategoriesData { String s = "SimpleCategoriesData:\n"; s += "shared : " + arrayToString(sharedDefaults) + "\n"; s += "map : \n"; - for (SingleChosenAnswer key : questionsSelections.keySet()) { - s += key + " : " + arrayToString(questionsSelections.get(key)) + "\n"; + for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) { + for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) { + s += "(" + questionNumber + ", " + answerNumber + ") -> " + + arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n"; + } } return s; } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 31911e6..d953246 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -1,75 +1,88 @@ package meerkat.voting.controller.selector; -import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; -import meerkat.protobuf.Voting.*; +import meerkat.protobuf.Voting.BallotAnswer; +import meerkat.protobuf.Voting.BallotQuestion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; /** - * Created by hai on 02/05/16. + * A simple implementation of a QuestionSelector. + * This implementation simply regards every single answer in the channel choice phase as an identifier of a category + * Every category is an array of ballot questions. + * Data of categories is initialized and stored by a SimpleCategoriesData object. + * After receiving the answers from a channel choice phase, this class simply gathers all the categories + * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question + * is included if its index appears in any chosen category, or in the default category shared by all voters) */ -public class SimpleListCategoriesSelector extends QuestionSelector { +public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + private BallotQuestion[] allBallotQuestions; + private SimpleCategoriesData selectionData; private boolean[] isSelected; - public SimpleListCategoriesSelector(Object selectionData, BallotQuestion[] allBallotQuestions) { - super(selectionData, allBallotQuestions); - initializeAttributes (allBallotQuestions); - } - public SimpleListCategoriesSelector(Object selectionData, ArrayList allBallotQuestions) { - super(selectionData, null); - BallotQuestion[] questionsArr = new BallotQuestion[allBallotQuestions.size()]; - for (int i = 0; i < questionsArr.length; ++i) { - questionsArr[i] = allBallotQuestions.get(i); - } - initializeAttributes (questionsArr); + public SimpleListCategoriesSelector() { + this.allBallotQuestions = null; + this.selectionData = null; } - private void initializeAttributes (BallotQuestion[] allBallotQuestions) { - assert selectionData instanceof SimpleCategoriesData; - this.allBallotQuestions = allBallotQuestions; - SimpleCategoriesData data = (SimpleCategoriesData) selectionData; - int maxQuestionNumber = data.getMaxQuestionNumber(); - int length = allBallotQuestions.length; - if (maxQuestionNumber >= length) { - String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + length + " questions totally"; - logger.error(errorMessage); - throw new ValueException(errorMessage); - } - isSelected = new boolean[allBallotQuestions.length]; - } - - @Override - public int getChannelIdentifier(BallotAnswer[] channelChoiceAnswers) { + public void setAllBallotQuestions(List allBallotQuestions) { + this.allBallotQuestions = (BallotQuestion[])allBallotQuestions.toArray(); + isSelected = new boolean[this.allBallotQuestions.length]; + assertDataValid(); + } + + @Override + public void setSelectionData(SelectionData data) { + if (! (data instanceof SimpleCategoriesData)) { + String errorMessage = "Initialization of SimpleListCategoriesSelector with wrong object type"; + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + this.selectionData = (SimpleCategoriesData)data; + assertDataValid(); + } + + private void assertDataValid () { + if (selectionData != null && allBallotQuestions != null) { + int questionsLength = allBallotQuestions.length; + int maxQuestionNumber = selectionData.getMaxQuestionNumber(); + if (maxQuestionNumber >= questionsLength) { + String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + questionsLength + " questions totally"; + logger.error(errorMessage); + throw new IndexOutOfBoundsException(errorMessage); + } + } + } + + @Override + public int getChannelIdentifier(List channelChoiceAnswers) { return 0; } @Override - public BallotQuestion[] selectQuestionsForVoter(BallotAnswer[] channelChoiceAnswers) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; + public List selectQuestionsForVoter(List channelChoiceAnswers) { java.util.Arrays.fill(isSelected, false); - markSelected(data.getSharedDefaults()); - markSelectionsOfVoterChannelChoice (channelChoiceAnswers); + markSelected(selectionData.getSharedDefaults()); + markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray()); int[] questionIndices = extractSelectedIndices(); - BallotQuestion[] selectedQuestions = new BallotQuestion[questionIndices.length]; - for (int i = 0; i < questionIndices.length; ++i) { - selectedQuestions[i] = allBallotQuestions[questionIndices[i]]; + List selectedQuestions = new ArrayList<>(); + for (int questionIndex: questionIndices) { + selectedQuestions.add(allBallotQuestions[questionIndex]); } return selectedQuestions; } private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; for (int q = 0; q < channelChoiceAnswers.length; ++q) { BallotAnswer ballotAnswer = channelChoiceAnswers[q]; assertAnswerLengthIsOne(ballotAnswer, q); - SingleChosenAnswer key = new SingleChosenAnswer(q, ballotAnswer.getAnswer(0)); - assertKeyInSelectionData(key); - markSelected(data.getItem(key)); + assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0)); + markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0))); } } @@ -81,17 +94,16 @@ public class SimpleListCategoriesSelector extends QuestionSelector { errorMessage += " " + i; } logger.error(errorMessage); - throw new ValueException(errorMessage); + throw new IllegalArgumentException(errorMessage); } } - private void assertKeyInSelectionData(SingleChosenAnswer key) { - SimpleCategoriesData data = (SimpleCategoriesData)selectionData; - int[] questionListToAdd = data.getItem(key); + private void assertKeyInSelectionData(int questionNumber, int answerNumber) { + int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber); if (null == questionListToAdd) { - String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + key.answerNumber + " for question number " + key.questionNumber; + String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + answerNumber + " for question number " + questionNumber; logger.error(errorMessage); - throw new ValueException(errorMessage); + throw new IllegalArgumentException(errorMessage); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java deleted file mode 100644 index fad377b..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SingleChosenAnswer.java +++ /dev/null @@ -1,31 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * Created by hai on 02/05/16. - */ -public class SingleChosenAnswer { - public int questionNumber; - public long answerNumber; - - public SingleChosenAnswer(int questionNumber, long answerNumber) { - this.questionNumber = questionNumber; - this.answerNumber = answerNumber; - } - - public String toString() { - return "SingleChosenAnswer(" + questionNumber + ", " + answerNumber + ")"; - } - - public boolean equals (Object other) { - if (!(other instanceof SingleChosenAnswer)) { - return false; - } - SingleChosenAnswer o = (SingleChosenAnswer)other; - return (o.questionNumber == this.questionNumber) && (o.answerNumber == this.answerNumber); - } - - @Override - public int hashCode () { - return questionNumber*1000 + (int)answerNumber; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 4b6486e..1ab1574 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -7,9 +7,7 @@ import meerkat.protobuf.Voting.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.Date; -import java.util.StringTokenizer; -import java.util.Timer; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import meerkat.voting.controller.callbacks.*; @@ -45,54 +43,47 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { logger.info("entered the voting flow"); while (true) { try { - UICommand task = queue.take(); - handleSingleTask (task); + UICommand command = queue.take(); + handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from task queue " + e); + logger.warn ("Interrupted while reading from command queue " + e); } } } - private void handleSingleTask (UICommand task) { - if (!(task instanceof TickCommand)) { + private void handleSingleCommand(UICommand command) { + if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { stopWaiting(); } } - if (task instanceof StartSessionUICommand) { - doShowWelcomeScreen((StartSessionUICommand)task); - return; + if (command instanceof StartSessionUICommand) { + doShowWelcomeScreen((StartSessionUICommand)command); } - else if (task instanceof ChannelChoiceUICommand) { - doAskChannelChoiceQuestions((ChannelChoiceUICommand)task); - return; + else if (command instanceof ChannelChoiceUICommand) { + doAskChannelChoiceQuestions((ChannelChoiceUICommand)command); } - else if (task instanceof RaceVotingUICommand) { - doAskVotingQuestions((RaceVotingUICommand)task); - return; + else if (command instanceof RaceVotingUICommand) { + doAskVotingQuestions((RaceVotingUICommand)command); } - else if (task instanceof CastOrAuditUICommand) { - doCastOrAudit ((CastOrAuditUICommand)task); - return; + else if (command instanceof CastOrAuditUICommand) { + doCastOrAudit ((CastOrAuditUICommand)command); } - else if (task instanceof HaltCommand) { - doHalt((HaltCommand)task); - return; + else if (command instanceof FatalErrorUICommand) { + doFatalError((FatalErrorUICommand)command); } - else if (task instanceof WaitForFinishCommand) { - doWaitForFinish((WaitForFinishCommand)task); - return; + else if (command instanceof WaitForFinishUICommand) { + doWaitForFinish((WaitForFinishUICommand)command); } - else if (task instanceof TickCommand) { + else if (command instanceof TickCommand) { doTick (); - return; } else { - String errorMessage = "handleSingleTask: unknown type of UICommand received: " + - task.getClass().getName(); + String errorMessage = "handleSingleCommand: unknown type of UICommand received: " + + command.getClass().getName(); logger.error(errorMessage); throw new RuntimeException(errorMessage); } @@ -105,13 +96,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new StartSessionUICommand((ControllerCallback)callback)); } - private void doShowWelcomeScreen(StartSessionUICommand task) { + private void doShowWelcomeScreen(StartSessionUICommand command) { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); waitForEnter(null); - ControllerCallback callback = task.getCallback(); + ControllerCallback callback = command.getCallback(); assert (callback instanceof NewVoterCallback); - ((NewVoterCallback)callback).onSuccess(null); + callback.onSuccess(null); } private void stopWaiting () { @@ -138,45 +129,45 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } @Override - public void chooseChannel(BallotQuestion[] questions, FutureCallback callback) { + public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand task = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); - queue.add(task); + ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + queue.add(command); } - private void doAskChannelChoiceQuestions (ChannelChoiceUICommand task) { + private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) { logger.debug("UI: doAskChannelChoiceQuestions"); System.out.println("Showing questions for choosing channel:\n"); try { - BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); - task.getCallback().onSuccess(answers); + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); } catch (IOException e) { String errorMessage = "Channel choice failed due to IOException: " + e; logger.error (errorMessage); System.err.println(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @Override - public void askVoterQuestions(BallotQuestion[] questions, FutureCallback callback) { + public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); } - private void doAskVotingQuestions (RaceVotingUICommand task) { + private void doAskVotingQuestions (RaceVotingUICommand command) { logger.debug("UI: doAskVotingQuestions"); System.out.println("Showing questions for race voting:\n"); try { - BallotAnswer[] answers = askVoterForAnswers(task.getQuestions()); - task.getCallback().onSuccess(answers); + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); } catch (IOException e) { String errorMessage = "Asking voting questions failed due to IOException: " + e; logger.error (errorMessage); System.err.println(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @@ -186,7 +177,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); } - private void doCastOrAudit(CastOrAuditUICommand task) { + private void doCastOrAudit(CastOrAuditUICommand command) { logger.debug("UI entered doCastOrAudit"); System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); @@ -203,30 +194,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { else { throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'"); } - ControllerCallback callback = task.getCallback(); + ControllerCallback callback = command.getCallback(); assert (callback instanceof CastOrAuditCallback); ((CastOrAuditCallback)callback).onSuccess(fChoice); } catch (IllegalArgumentException|IOException e) { String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e; logger.error(errorMessage); - task.getCallback().onFailure(e); + command.getCallback().onFailure(e); } } @Override - public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { + public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishCommand(message, (ControllerCallback)callback)); + queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); } - public void doWaitForFinish (WaitForFinishCommand task) { + public void doWaitForFinish (WaitForFinishUICommand command) { logger.debug("UI entered doWaitForFinish"); startWaitingTime = new Date(); - UIElement message = task.getMessage(); + UIElement message = command.getMessage(); String messageString; if (message.getType() != UIElementDataType.TEXT) { messageString = "Default message: encountered an error. System halting"; @@ -240,39 +231,57 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageAndHalt"); - queue.add(new HaltCommand(errorMessage, (ControllerCallback)callback)); + throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it."); } - private void doHalt (HaltCommand task) { - logger.debug("UI entered doHalt"); - UIElement errorMessage = task.getErrorMessage(); + @Override + public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageWithButtons"); + queue.clear(); + queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + } + + private void doFatalError (FatalErrorUICommand command) { + logger.debug("UI entered doFatalError"); + + UIElement errorMessage = command.getErrorMessage(); String errorMessageString; if (errorMessage.getType() != UIElementDataType.TEXT) { errorMessageString = "Default message: encountered an error. System halting"; } else { errorMessageString = bytesToString(errorMessage.getData()); } - System.out.println(errorMessageString); - while (true) { - try { - wait(); - } catch (InterruptedException e) { - logger.error("UI halt has been interrupted. Details: " + e); - ControllerCallback callback = task.getCallback(); - assert callback instanceof HaltCallback; - ((HaltCallback) callback).onFailure(e); + UIElement[] buttonLabels = command.getButtonLabels(); + String[] buttonLabelStrings = new String[buttonLabels.length]; + for (int i = 0; i < buttonLabels.length; ++i) { + if (buttonLabels[i].getType() != UIElementDataType.TEXT) { + buttonLabelStrings[i] = ""; + } else { + buttonLabelStrings[i] = bytesToString(errorMessage.getData()); } } + + System.out.println(errorMessageString); + for (int i = 0; i < buttonLabelStrings.length; ++i) { + System.out.println("" + i + " - " + buttonLabelStrings[i]); + } + + try { + String s = readInputLine(); + Integer chosenButton = new Integer(s); + command.getCallback().onSuccess(chosenButton); + } + catch (IOException e) { + String err = "doFatalError: some error with reading input from console. details: " + e; + logger.error(err); + command.getCallback().onFailure(e); + } + } - @Override - public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { - throw new UnsupportedOperationException(); - } - private void doTick () { if (startWaitingTime != null) { System.out.print ("."); // still waiting @@ -295,9 +304,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } - private void assertQuestionsAreValid (BallotQuestion[] questions) { - for (int index = 0; index < questions.length; ++index) { - BallotQuestion question = questions[index]; + private void assertQuestionsAreValid (List questions) { + for (int index = 0; index < questions.size(); ++index) { + BallotQuestion question = questions.get(index); if (question.getIsMandatory()) { String errorMessage = "askVoterQuestions: question number " + index + " is marked as mandatory"; logger.error(errorMessage); @@ -311,14 +320,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private BallotAnswer[] askVoterForAnswers(BallotQuestion[] questions) throws IOException { + private List askVoterForAnswers(List questions) throws IOException { assertQuestionsAreValid (questions); - BallotAnswer answers[] = new BallotAnswer[questions.length]; + List answers = new ArrayList<>(); int index = 0; - while (index < questions.length) { - BallotQuestion question = questions[index]; + while (index < questions.size()) { + BallotQuestion question = questions.get(index); System.out.println("Question number " + index); showQuestionOnScreen(question); @@ -330,13 +339,14 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } else if (s.equals("back") || s.equals("b")) { --index; + answers.remove(index); } else if (s.equals("skip") || s.equals("s")) { - answers[index] = translateStringAnswerToProtoBufMessageAnswer(""); + answers.add(translateStringAnswerToProtoBufMessageAnswer("")); ++index; } else { - answers[index] = translateStringAnswerToProtoBufMessageAnswer(s); + answers.add(translateStringAnswerToProtoBufMessageAnswer(s)); ++index; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index ae96f7b..192dd1c 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -3,6 +3,8 @@ package meerkat.voting.ui; import com.google.common.util.concurrent.FutureCallback; import meerkat.protobuf.Voting.*; +import java.util.List; + /** * An interface for the user interface component of the voting booth @@ -25,14 +27,14 @@ public interface VotingBoothUI { * @param questions questions to determine the right voting channel for this voter * @param callback that's where we store the answers to decide channel upon for the current voter */ - public void chooseChannel (BallotQuestion[] questions, FutureCallback callback); + public void chooseChannel (List questions, FutureCallback> callback); /** * Presents the set of questions to the voter. Collect all his responses. * @param questions all ballot questions to present to the voter * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session */ - public void askVoterQuestions (BallotQuestion[] questions, FutureCallback callback); + public void askVoterQuestions (List questions, FutureCallback> callback); /** * Get a response from the voter on how to finalize the ballot. @@ -51,7 +53,7 @@ public interface VotingBoothUI { * @param message a message to show the user on the UI device while waiting * @param callback a success return value of the wait (cancelling returns false) */ - public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); + public void notifyVoterToWaitForFinish (UIElement message, FutureCallback callback); /** * show a fatal error message in the UI. Halts system. Waits for administrator interrupt or reset diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 993f64b..1b2f72f 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 21/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index 22d2ff3..5ad4391 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -1,22 +1,24 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; + +import java.util.List; /** * Created by hai on 18/04/16. */ public class ChannelChoiceUICommand extends UICommand { - private final BallotQuestion[] questions; + private final List questions; - public ChannelChoiceUICommand(BallotQuestion[] questions, ControllerCallback callback) + public ChannelChoiceUICommand(List questions, ControllerCallback callback) { super(callback); this.questions = questions; } - public BallotQuestion[] getQuestions () { + public List getQuestions () { return this.questions; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java new file mode 100644 index 0000000..7679130 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -0,0 +1,28 @@ +package meerkat.voting.ui.uicommands; + +import meerkat.protobuf.Voting.UIElement; +import meerkat.voting.controller.callbacks.*; + +/** + * Created by hai on 18/04/16. + */ +public class FatalErrorUICommand extends UICommand { + + private final UIElement errorMessage; + private final UIElement[] buttonLabels; + + public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) + { + super(callback); + this.errorMessage = errorMessage; + this.buttonLabels = buttonLabels; + } + + public UIElement getErrorMessage() { + return this.errorMessage; + } + + public UIElement[] getButtonLabels() { + return this.getButtonLabels(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java deleted file mode 100644 index 5213354..0000000 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/HaltCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package meerkat.voting.ui.uicommands; - -import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; - -/** - * Created by hai on 18/04/16. - */ -public class HaltCommand extends UICommand { - - private final UIElement errorMessage; - - public HaltCommand(UIElement errorMessage, ControllerCallback callback) - { - super(callback); - this.errorMessage = errorMessage; - } - - public UIElement getErrorMessage () { - return this.errorMessage; - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 31d2706..6430e59 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -1,22 +1,24 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; + +import java.util.List; /** * Created by hai on 18/04/16. */ public class RaceVotingUICommand extends UICommand { - private final BallotQuestion[] questions; + private final List questions; - public RaceVotingUICommand(BallotQuestion[] questions, ControllerCallback callback) + public RaceVotingUICommand(List questions, ControllerCallback callback) { super(callback); this.questions = questions; } - public BallotQuestion[] getQuestions () { + public List getQuestions () { return this.questions; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index f1bc146..393afa7 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 3192f4c..0872ea3 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index b22fdef..460b7d0 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -1,6 +1,6 @@ package meerkat.voting.ui.uicommands; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; //TODO: make this class generic public abstract class UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java similarity index 60% rename from voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java rename to voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index fe9b1cc..5c48359 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -1,17 +1,17 @@ package meerkat.voting.ui.uicommands; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.*; /** * Created by hai on 18/04/16. */ -public class WaitForFinishCommand extends UICommand { +public class WaitForFinishUICommand extends UICommand { private final UIElement message; - public WaitForFinishCommand(UIElement message, ControllerCallback callback) + public WaitForFinishUICommand(UIElement message, ControllerCallback callback) { super(callback); this.message = message; From 347e826f7309a6574d163e319bbfbcfa3bdf405a Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Tue, 31 May 2016 15:26:56 +0300 Subject: [PATCH 056/106] Working integrated version of Scanner WebApp Fully testsed Moved BoolMsg and IntMsg to Comm package (from BulletinBoardAPI) --- .../SimpleBulletinBoardClient.java | 9 +- .../SingleServerCloseBatchWorker.java | 2 +- .../SingleServerGenericPostWorker.java | 2 +- .../GenericBulletinBoardClientTester.java | 2 +- .../sqlserver/BulletinBoardSQLServer.java | 2 +- .../webapp/BulletinBoardWebApp.java | 2 +- ...BulletinBoardSQLServerIntegrationTest.java | 2 +- .../GenericBulletinBoardServerTest.java | 2 +- .../bulletinboard/BulletinBoardServer.java | 5 +- .../PollingStationConstants.java | 2 - .../pollingstation/PollingStationScanner.java | 54 ++++-- .../main/proto/meerkat/BulletinBoardAPI.proto | 8 - .../main/proto/meerkat/PollingStation.proto | 7 + .../src/main/proto/meerkat/comm.proto | 8 + polling-station/build.gradle | 7 +- .../PollingStationScannerWebApp.java | 89 +++++++++ .../PollingStationWebScanner.java | 91 +++++----- .../src/main/webapp/META-INF/jetty-env.xml | 12 -- .../src/main/webapp/WEB-INF/web.xml | 20 --- .../PollingStationWebScannerTest.java | 169 ++++++++++++++++++ 20 files changed, 374 insertions(+), 121 deletions(-) create mode 100644 polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java delete mode 100644 polling-station/src/main/webapp/META-INF/jetty-env.xml delete mode 100644 polling-station/src/main/webapp/WEB-INF/web.xml create mode 100644 polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 80451b8..26b1e4e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -1,21 +1,14 @@ 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.Comm.*; 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; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java index ab298a5..83e27c2 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerCloseBatchWorker.java @@ -6,7 +6,7 @@ import static meerkat.bulletinboard.BulletinBoardConstants.CLOSE_BATCH_PATH; /** * Created by Arbel Deutsch Peled on 27-Dec-15. - * Tries to contact server once and perform a close batch operation + * Tries to contact server once and perform a stop batch operation */ public class SingleServerCloseBatchWorker extends SingleServerGenericPostWorker { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java index 621a828..2148801 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java @@ -2,7 +2,7 @@ package meerkat.bulletinboard.workers.singleserver; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.BoolMsg; +import meerkat.protobuf.Comm.*; import meerkat.rest.Constants; import javax.ws.rs.ProcessingException; diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java index 88fb22c..d4bd3ec 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java @@ -508,7 +508,7 @@ public class GenericBulletinBoardClientTester { .build()) .build(); - // Try to close the (unopened) batch; + // Try to stop the (unopened) batch; bulletinBoardClient.closeBatch(closeBatchMessage, failPostCallback); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index b652b1a..dd68daf 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -17,6 +17,7 @@ import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; @@ -27,7 +28,6 @@ import javax.sql.DataSource; import meerkat.util.BulletinBoardUtils; import meerkat.util.TimestampComparator; -import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 5f98ff6..f88d31f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -15,8 +15,8 @@ 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 meerkat.protobuf.Comm.*; import static meerkat.bulletinboard.BulletinBoardConstants.*; import static meerkat.rest.Constants.*; diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java index 8debb83..a9be646 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java @@ -8,6 +8,7 @@ import com.google.protobuf.Timestamp; import meerkat.comm.MessageInputStream; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm.*; import static meerkat.bulletinboard.BulletinBoardConstants.*; import meerkat.rest.Constants; import meerkat.rest.ProtobufMessageBodyReader; @@ -20,7 +21,6 @@ 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; diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 131aee8..e09f051 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -28,8 +28,8 @@ import meerkat.crypto.Digest; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm.*; import meerkat.util.BulletinBoardMessageGenerator; -import org.h2.util.DateTimeUtils; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index f6ca1ab..abe4335 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -3,6 +3,7 @@ package meerkat.bulletinboard; import meerkat.comm.CommunicationException; import meerkat.comm.MessageOutputStream; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm.*; import java.util.Collection; @@ -62,8 +63,8 @@ public interface BulletinBoardServer{ 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 + * Attempts to stop and finalize a batch message + * @param message contains the data necessary to stop 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 diff --git a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java index 643a73c..1bc6d3c 100644 --- a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java +++ b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationConstants.java @@ -7,9 +7,7 @@ public interface PollingStationConstants { // Relative addresses for Scanner operations - public static final String POLLING_STATION_WEB_SCANNER_PATH = "/scanner"; public static final String POLLING_STATION_WEB_SCANNER_SCAN_PATH = "/scan"; public static final String POLLING_STATION_WEB_SCANNER_ERROR_PATH = "/error"; - } diff --git a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java index 9bea5b5..9adc616 100644 --- a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java +++ b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java @@ -1,29 +1,61 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.Comm.BoolMsg; import meerkat.protobuf.PollingStation.*; /** * Created by Arbel on 05/05/2016. * An interface for the scanner used by the Polling Station Committee + * The scanner works as a producer, while the polling station is the consumer + * That is to say: scans are pushed from the scanner rather than requested by the polling station */ public interface PollingStationScanner { /** - * Subscribes to new scans - * @param scanCallback is the handler for scanned data + * An interface for processing scans (Polling Station side) */ - public void subscribe(FutureCallback scanCallback); + public interface Consumer { + + /** + * Sets up the connection to the scanner and begins receiving scans + * @throws Exception when the operation fails + */ + public void start() throws Exception; + + /** + * Closes the connection to the scanner + * @throws Exception when the operation fails + */ + public void stop() throws Exception; + + /** + * Subscribes to new scans + * + * @param scanCallback is the handler for scanned data + */ + public void subscribe(FutureCallback scanCallback); + + } /** - * Sends a scan to all subscribers - * @param scannedData contains the scanned data + * An interface for submitting scanned data (scanner side) */ - public void newScan(ScannedData scannedData); + public interface Producer { - /** - * Notifies subscribers about an error that occurred during scan - * @param errorMsg is the error that occurred - */ - public void reportScanError(ErrorMsg errorMsg); + /** + * Sends a scan to all subscribers + * @param scannedData contains the scanned data + * @return a BoolMsg containing TRUE iff the scanned data has been sent to at least one subscriber + */ + public BoolMsg newScan(ScannedData scannedData); + /** + * Notifies subscribers about an error that occurred during scan + * @param errorMsg is the error that occurred + * @return a BoolMsg containing TRUE iff the error has been sent to at least one subscriber + */ + public BoolMsg reportScanError(ErrorMsg errorMsg); + + } + } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 0edb03b..27ad512 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -7,14 +7,6 @@ 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. diff --git a/meerkat-common/src/main/proto/meerkat/PollingStation.proto b/meerkat-common/src/main/proto/meerkat/PollingStation.proto index 0cdc658..35dbd12 100644 --- a/meerkat-common/src/main/proto/meerkat/PollingStation.proto +++ b/meerkat-common/src/main/proto/meerkat/PollingStation.proto @@ -12,4 +12,11 @@ message ScannedData { // Container for error messages message ErrorMsg { string msg = 1; +} + +// Container for HTTP address +message HTTPAddress { + string hostname = 1; + int32 port = 2; + string address = 3; } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/comm.proto b/meerkat-common/src/main/proto/meerkat/comm.proto index c509165..2f23678 100644 --- a/meerkat-common/src/main/proto/meerkat/comm.proto +++ b/meerkat-common/src/main/proto/meerkat/comm.proto @@ -11,3 +11,11 @@ message BroadcastMessage { bytes payload = 5; } + +message BoolMsg { + bool value = 1; +} + +message IntMsg { + int32 value = 1; +} diff --git a/polling-station/build.gradle b/polling-station/build.gradle index 036d2e8..4635668 100644 --- a/polling-station/build.gradle +++ b/polling-station/build.gradle @@ -2,10 +2,8 @@ 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' @@ -46,10 +44,11 @@ dependencies { compile project(':restful-api-common') // Jersey for RESTful API - compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' + compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.5.+' // Servlets - compile 'javax.servlet:javax.servlet-api:3.0.+' + compile 'org.eclipse.jetty:jetty-server:9.3.+' + compile 'org.eclipse.jetty:jetty-servlet:9.3.+' // Logging compile 'org.slf4j:slf4j-api:1.7.7' diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java new file mode 100644 index 0000000..edebe33 --- /dev/null +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java @@ -0,0 +1,89 @@ +package meerkat.pollingstation; + +/** + * Created by Arbel on 5/31/2016. + */ + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.protobuf.Comm; +import meerkat.protobuf.PollingStation; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import java.io.IOException; +import java.util.Iterator; + +import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH; +import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; +import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF; + +/** + * Implements a Web-App interface for {@link meerkat.pollingstation.PollingStationScanner.Producer} + * This class depends on {@link meerkat.pollingstation.PollingStationWebScanner} and works in conjunction with it + */ +@Path("/") +public class PollingStationScannerWebApp implements PollingStationScanner.Producer { + + @Context + ServletContext servletContext; + + Iterator> callbacks; + + /** + * This method is called by the Jetty engine when instantiating the servlet + */ + @PostConstruct + public void init() throws Exception{ + callbacks = ((PollingStationWebScanner.CallbackAccessor) servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME)).getCallbackIterator(); + } + + @POST + @Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) + @Override + public Comm.BoolMsg newScan(PollingStation.ScannedData scannedData) { + + boolean handled = false; + + while (callbacks.hasNext()){ + + callbacks.next().onSuccess(scannedData); + handled = true; + + } + + return Comm.BoolMsg.newBuilder() + .setValue(handled) + .build(); + + } + + @POST + @Path(POLLING_STATION_WEB_SCANNER_ERROR_PATH) + @Consumes(MEDIATYPE_PROTOBUF) + @Produces(MEDIATYPE_PROTOBUF) + @Override + public Comm.BoolMsg reportScanError(PollingStation.ErrorMsg errorMsg) { + + boolean handled = false; + + while (callbacks.hasNext()){ + + callbacks.next().onFailure(new IOException(errorMsg.getMsg())); + handled = true; + + } + + return Comm.BoolMsg.newBuilder() + .setValue(handled) + .build(); + + } + +} diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java index a3aefdd..d7fc6a4 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java @@ -1,27 +1,57 @@ package meerkat.pollingstation; -import com.google.common.util.concurrent.FutureCallback; -import meerkat.protobuf.PollingStation; -import static meerkat.rest.Constants.*; - -import javax.ws.rs.*; -import java.io.IOException; -import java.util.LinkedList; +import java.util.Iterator; import java.util.List; +import java.util.LinkedList; + +import com.google.common.util.concurrent.FutureCallback; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.*; -import static meerkat.pollingstation.PollingStationConstants.*; import meerkat.protobuf.PollingStation.*; +import org.glassfish.jersey.servlet.ServletContainer; +import org.glassfish.jersey.server.ResourceConfig; + +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.rest.*; /** * Created by Arbel on 05/05/2016. */ -@Path(POLLING_STATION_WEB_SCANNER_PATH) -public class PollingStationWebScanner implements PollingStationScanner{ +public class PollingStationWebScanner implements PollingStationScanner.Consumer{ + + public final static String CALLBACKS_ATTRIBUTE_NAME = "callbacks"; + + private final Server server; private final List> callbacks; - public PollingStationWebScanner() { + public PollingStationWebScanner(HTTPAddress address) { + callbacks = new LinkedList<>(); + + server = new Server(address.getPort()); + + ServletContextHandler servletContextHandler = new ServletContextHandler(server, address.getAddress()); + servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, new CallbackAccessor()); + + ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class); + resourceConfig.register(ProtobufMessageBodyReader.class); + resourceConfig.register(ProtobufMessageBodyWriter.class); + + ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); + + servletContextHandler.addServlet(servletHolder, "/*"); + } + + @Override + public void start() throws Exception { + server.start(); + } + + @Override + public void stop() throws Exception { + server.stop(); } @Override @@ -29,43 +59,10 @@ public class PollingStationWebScanner implements PollingStationScanner{ callbacks.add(scanCallback); } - @Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH) - @POST - @Consumes(MEDIATYPE_PROTOBUF) - @Produces(MEDIATYPE_PROTOBUF) - @Override - public void newScan(ScannedData scannedData) { - - if (callbacks.size() <= 0) - throw new RuntimeException("No subscribers to forward scan to!"); - - for (FutureCallback callback : callbacks){ - callback.onSuccess(scannedData); + public class CallbackAccessor { + public Iterator> getCallbackIterator() { + return callbacks.iterator(); } - } - @Path(POLLING_STATION_WEB_SCANNER_ERROR_PATH) - @POST - @Consumes(MEDIATYPE_PROTOBUF) - @Produces(MEDIATYPE_PROTOBUF) - @Override - public void reportScanError(PollingStation.ErrorMsg errorMsg) { - - if (callbacks.size() <= 0) - throw new RuntimeException("No subscribers to forward error to!"); - - for (FutureCallback callback : callbacks){ - callback.onFailure(new IOException(errorMsg.getMsg())); - } - - } - - @Path("/test") - @GET - public String test(){ - return "test"; - } - - } diff --git a/polling-station/src/main/webapp/META-INF/jetty-env.xml b/polling-station/src/main/webapp/META-INF/jetty-env.xml deleted file mode 100644 index c4d368f..0000000 --- a/polling-station/src/main/webapp/META-INF/jetty-env.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern - none - - - org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern - none - - \ No newline at end of file diff --git a/polling-station/src/main/webapp/WEB-INF/web.xml b/polling-station/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 0632b0d..0000000 --- a/polling-station/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - Jersey Hello World - - org.glassfish.jersey.servlet.ServletContainer - - - jersey.config.server.provider.packages - meerkat - - 1 - - - Jersey Hello World - /* - - - meerkat.pollingstation.PollingStationWebScanner - - diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java new file mode 100644 index 0000000..63cd8dd --- /dev/null +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -0,0 +1,169 @@ +package meerkat.pollingstation; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import com.sun.org.apache.regexp.internal.RE; +import meerkat.protobuf.PollingStation; +import meerkat.protobuf.PollingStation.*; +import meerkat.rest.Constants; + +import meerkat.rest.*; +import org.junit.After; +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.Response; + +import java.io.IOException; +import java.util.concurrent.Semaphore; + +import static meerkat.pollingstation.PollingStationConstants.*; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Created by Arbel on 25/05/2016. + */ +public class PollingStationWebScannerTest { + + private PollingStationScanner.Consumer scanner; + private HTTPAddress httpAddress; + + private Semaphore semaphore; + private Throwable thrown; + private boolean dataIsAsExpected; + + private class ScanHandler implements FutureCallback { + + private final ScannedData expectedData; + + public ScanHandler(ScannedData expectedData) { + this.expectedData = expectedData; + } + + @Override + public void onSuccess(ScannedData result) { + dataIsAsExpected = result.getData().equals(expectedData.getData()); + semaphore.release(); + } + + @Override + public void onFailure(Throwable t) { + dataIsAsExpected = false; + thrown = t; + semaphore.release(); + } + } + + private class ErrorHandler implements FutureCallback { + + private final String expectedErrorMessage; + + public ErrorHandler(String expectedErrorMessage) { + this.expectedErrorMessage = expectedErrorMessage; + } + + @Override + public void onSuccess(ScannedData result) { + dataIsAsExpected = false; + semaphore.release(); + } + + @Override + public void onFailure(Throwable t) { + dataIsAsExpected = t.getMessage().equals(expectedErrorMessage); + semaphore.release(); + } + } + + @Before + public void init() { + + System.err.println("Setting up Scanner WebApp!"); + + httpAddress = HTTPAddress.newBuilder() + .setPort(8080) + .setHostname("http://localhost") + .build(); + + scanner = new PollingStationWebScanner(httpAddress); + + semaphore = new Semaphore(0); + thrown = null; + + try { + scanner.start(); + } catch (Exception e) { + assertThat("Could not start server: " + e.getMessage(), false); + } + + } + + @Test + public void testSuccessfulScan() throws InterruptedException { + + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + WebTarget webTarget = client.target(httpAddress.getHostname() + ":" + httpAddress.getPort()) + .path(httpAddress.getAddress()).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + + byte[] data = {(byte) 1, (byte) 2}; + + ScannedData scannedData = ScannedData.newBuilder() + .setData(ByteString.copyFrom(data)) + .build(); + + scanner.subscribe(new ScanHandler(scannedData)); + + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + response.close(); + + semaphore.acquire(); + assertThat("Scanner has thrown an error", thrown == null); + assertThat("Scanned data received was incorrect", dataIsAsExpected); + + } + + @Test + public void testErroneousScan() throws InterruptedException { + + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + WebTarget webTarget = client.target(httpAddress.getHostname() + ":" + httpAddress.getPort()) + .path(httpAddress.getAddress()).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + + ErrorMsg errorMsg = ErrorMsg.newBuilder() + .setMsg("!Error Message!") + .build(); + + scanner.subscribe(new ErrorHandler(errorMsg.getMsg())); + + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(errorMsg, Constants.MEDIATYPE_PROTOBUF)); + response.close(); + + semaphore.acquire(); + assertThat("Scanner error received was incorrect", dataIsAsExpected); + + } + + @After + public void close() { + + System.err.println("Scanner WebApp shutting down..."); + + try { + scanner.stop(); + } catch (Exception e) { + assertThat("Could not stop server: " + e.getMessage(), false); + } + + } + +} \ No newline at end of file From 7c60e487cc129d791e3bdb1c9c8a69f9d7e14507 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Wed, 1 Jun 2016 21:34:17 +0300 Subject: [PATCH 057/106] Created a test for the Synchronizer. Not passing yet. --- .../SimpleBulletinBoardClient.java | 57 ++--- .../SimpleBulletinBoardSynchronizer.java | 110 +++++++- .../SingleServerGetRedundancyWorker.java | 2 - .../BulletinBoardSynchronizerTest.java | 241 ++++++++++++++++++ .../sqlserver/BulletinBoardSQLServer.java | 3 - .../sqlserver/H2QueryProvider.java | 8 +- .../BulletinBoardSynchronizer.java | 4 +- .../util/BulletinBoardMessageGenerator.java | 133 +++++++++- 8 files changed, 490 insertions(+), 68 deletions(-) create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 28252ae..579ecf9 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -1,22 +1,13 @@ package meerkat.bulletinboard; import com.google.protobuf.ByteString; -import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.singleserver.*; 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; @@ -68,7 +59,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { WebTarget webTarget; - Response response; + Response response = null; // Post message to all databases try { @@ -80,10 +71,17 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ if (response.getStatusInfo() == Response.Status.OK || response.getStatusInfo() == Response.Status.CREATED) { response.readEntity(BoolMsg.class).getValue(); + } else { + throw new CommunicationException("Server returned error. Status was: " + response.getStatus()); } } } catch (Exception e) { // Occurs only when server replies with valid status but invalid data - throw new CommunicationException("Error accessing database: " + e.getMessage()); + + throw new CommunicationException("Server returned invalid data type: " + e.getMessage()); + + } finally { + if (response != null) + response.close(); } // Calculate the correct message ID and return it @@ -100,36 +98,33 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ int batchID = completeBatch.getBeginBatchMessage().getBatchId(); // Post message to all databases - try { - for (String db : meerkatDBs) { - SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(db, completeBatch.getBeginBatchMessage(), 0); + for (String db : meerkatDBs) { - beginBatchWorker.call(); + SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(db, completeBatch.getBeginBatchMessage(), 0); - BatchMessage.Builder builder = BatchMessage.newBuilder().setSignerId(signerID).setBatchId(batchID); + beginBatchWorker.call(); - for (BatchData batchData : completeBatch.getBatchDataList()) { + BatchMessage.Builder builder = BatchMessage.newBuilder().setSignerId(signerID).setBatchId(batchID); - SingleServerPostBatchWorker postBatchWorker = - new SingleServerPostBatchWorker( - db, - builder.setData(batchData).setSerialNum(pos).build(), - 0); + for (BatchData batchData : completeBatch.getBatchDataList()) { - postBatchWorker.call(); + SingleServerPostBatchWorker postBatchWorker = + new SingleServerPostBatchWorker( + db, + builder.setData(batchData).setSerialNum(pos).build(), + 0); - pos++; + postBatchWorker.call(); - } - - SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(db, completeBatch.getCloseBatchMessage(), 0); - - closeBatchWorker.call(); + pos++; } - } catch (Exception e) { // Occurs only when server replies with valid status but invalid data - throw new CommunicationException("Error accessing database: " + e.getMessage()); + + SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(db, completeBatch.getCloseBatchMessage(), 0); + + closeBatchWorker.call(); + } digest.update(completeBatch); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index d96864a..f7e9baa 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -8,6 +8,8 @@ import meerkat.util.BulletinBoardUtils; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; /** * Created by Arbel on 13/04/2016. @@ -25,24 +27,75 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private static final MessageFilterList EMPTY_FILTER = MessageFilterList.getDefaultInstance(); private static final int SLEEP_INTERVAL = 10000; // 10 Seconds + private static final int WAIT_CAP = 300000; // 5 minutes wait before deciding that the sync has failed fatally + private Semaphore semaphore; + + /** + * This class is a callback that deletes a message if it has been successfully posted + * It also calls a stored callback + */ private class MessageDeleteCallback implements FutureCallback { private final long entryNum; + private final FutureCallback callback; - public MessageDeleteCallback(long entryNum) { + public MessageDeleteCallback(long entryNum, FutureCallback callback) { this.entryNum = entryNum; + this.callback = callback; } @Override public void onSuccess(Boolean result) { // Success: delete from database localClient.deleteMessage(entryNum, null); + callback.onSuccess(null); } @Override public void onFailure(Throwable t) { - // Ignore + callback.onFailure(t); + } + + } + + /** + * This class aggregates the results from all of the post operations + * If any post has failed: it changes the sync status to SERVER_ERROR + * It also notifies the main sync loop when all uploads are finished + */ + private class SyncStatusUpdateCallback implements FutureCallback { + + private int count; + private boolean errorEncountered; + + public SyncStatusUpdateCallback(int count) { + this.count = count; + this.errorEncountered = false; + } + + private void handleStatusUpdate() { + count--; + if (count <= 0) { + + if (errorEncountered) + updateSyncStatus(SyncStatus.SERVER_ERROR); + + // Upload is done: wake up the synchronizer loop + semaphore.release(); + + } + } + + @Override + public void onSuccess(Void result) { + handleStatusUpdate(); + } + + @Override + public void onFailure(Throwable t) { + errorEncountered = true; + handleStatusUpdate(); } } @@ -52,6 +105,20 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize @Override public void onSuccess(List result) { + // Notify Message Count callbacks if needed + + if (syncStatus != SyncStatus.SYNCHRONIZED || result.size() > 0) { + + for (FutureCallback callback : messageCountCallbacks){ + callback.onSuccess(result.size()); + } + + } + + // Handle upload and status change + + SyncStatusUpdateCallback syncStatusUpdateCallback = new SyncStatusUpdateCallback(result.size()); + SyncStatus newStatus = SyncStatus.PENDING; if (result.size() == 0) { @@ -79,20 +146,21 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize CompleteBatch completeBatch = localClient.readBatch(batchSpecificationMessage); - remoteClient.postBatch(completeBatch); + remoteClient.postBatch(completeBatch, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); } else { // This is a regular message: post it - - remoteClient.postMessage(message); + remoteClient.postMessage(message, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); } localClient.deleteMessage(message.getEntryNum()); } catch (CommunicationException e) { + // This is an error with the local server + // TODO: log updateSyncStatus(SyncStatus.SERVER_ERROR); } @@ -143,6 +211,8 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize messageCountCallbacks = new LinkedList<>(); syncStatusCallbacks = new LinkedList<>(); + semaphore = new Semaphore(0); + } @Override @@ -185,18 +255,32 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize while (syncStatus != SyncStatus.STOPPED) { - try { + do { + + if (syncStatus == SyncStatus.PENDING || syncStatus == SyncStatus.SERVER_ERROR) { - do { localClient.readMessages(EMPTY_FILTER, callback); - } while (syncStatus == SyncStatus.PENDING); - synchronized (this) { - this.wait(SLEEP_INTERVAL); } + try { + + semaphore.tryAcquire(WAIT_CAP, TimeUnit.MILLISECONDS); + //TODO: log hard error. Too much time trying to upload data. + + } catch (InterruptedException ignored) { + // We expect an interruption when the upload will complete + } + + + } while (syncStatus == SyncStatus.PENDING); + + // Database is synced. Wait for new data. + + try { + semaphore.tryAcquire(SLEEP_INTERVAL, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - e.printStackTrace(); + //TODO: log (probably nudged) } } @@ -207,9 +291,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize @Override public void nudge() { - synchronized (this) { - this.notify(); - } + semaphore.release(); } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java index 0401a76..23c07af 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGetRedundancyWorker.java @@ -6,7 +6,6 @@ import meerkat.comm.MessageInputStream; import meerkat.protobuf.BulletinBoardAPI.*; 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; @@ -14,7 +13,6 @@ import javax.ws.rs.core.Response; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; import static meerkat.bulletinboard.BulletinBoardConstants.READ_MESSAGES_PATH; diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java new file mode 100644 index 0000000..a3ace28 --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java @@ -0,0 +1,241 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; + +import static meerkat.bulletinboard.BulletinBoardSynchronizer.SyncStatus; + +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; +import meerkat.bulletinboard.sqlserver.H2QueryProvider; + +import meerkat.comm.CommunicationException; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.util.BulletinBoardMessageComparator; +import meerkat.util.BulletinBoardMessageGenerator; +import org.junit.*; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; + +import java.io.IOException; +import java.io.InputStream; +import java.security.*; +import java.security.cert.CertificateException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.Semaphore; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +/** + * Created by Arbel on 6/1/2016. + */ +public class BulletinBoardSynchronizerTest { + + private static final String REMOTE_SERVER_ADDRESS = "remoteDB"; + private static final String LOCAL_SERVER_ADDRESS = "localDB"; + + private static final int THREAD_NUM = 3; + private static final int SUBSCRIPTION_INTERVAL = 1000; + + private DeletableSubscriptionBulletinBoardClient localClient; + private AsyncBulletinBoardClient remoteClient; + + private BulletinBoardSynchronizer synchronizer; + + private static BulletinBoardMessageGenerator messageGenerator; + private static BulletinBoardMessageComparator messageComparator; + + private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; + private static String KEYFILE_PASSWORD1 = "secret"; + private static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt"; + + private static GenericBatchDigitalSignature[] signers; + private static ByteString[] signerIDs; + + private Semaphore semaphore; + private List thrown; + + @BeforeClass + public static void build() { + + messageGenerator = new BulletinBoardMessageGenerator(new Random(0)); + messageComparator = new BulletinBoardMessageComparator(); + + signers = new GenericBatchDigitalSignature[1]; + signerIDs = new ByteString[1]; + + signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + + InputStream keyStream = BulletinBoardSynchronizerTest.class.getResourceAsStream(KEYFILE_EXAMPLE); + char[] password = KEYFILE_PASSWORD1.toCharArray(); + + try { + + KeyStore.Builder keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); + + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(BulletinBoardSynchronizerTest.class.getResourceAsStream(CERT1_PEM_EXAMPLE)); + + } catch (IOException e) { + System.err.println("Failed reading from signature file " + e.getMessage()); + fail("Failed reading from signature file " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("Failed reading certificate " + e.getMessage()); + fail("Failed reading certificate " + e.getMessage()); + } catch (KeyStoreException e) { + System.err.println("Failed reading keystore " + e.getMessage()); + fail("Failed reading keystore " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.err.println("Couldn't find signing algorithm " + e.getMessage()); + fail("Couldn't find signing algorithm " + e.getMessage()); + } catch (UnrecoverableKeyException e) { + System.err.println("Couldn't find signing key " + e.getMessage()); + fail("Couldn't find signing key " + e.getMessage()); + } + + signerIDs[0] = signers[0].getSignerID(); + + } + + @Before + public void init() throws CommunicationException { + + DeletableBulletinBoardServer remoteServer = new BulletinBoardSQLServer(new H2QueryProvider(REMOTE_SERVER_ADDRESS)); + remoteServer.init(REMOTE_SERVER_ADDRESS); + + remoteClient = new LocalBulletinBoardClient( + remoteServer, + THREAD_NUM, + SUBSCRIPTION_INTERVAL); + + DeletableBulletinBoardServer localServer = new BulletinBoardSQLServer(new H2QueryProvider(LOCAL_SERVER_ADDRESS)); + localServer.init(LOCAL_SERVER_ADDRESS); + + localClient = new LocalBulletinBoardClient( + localServer, + THREAD_NUM, + SUBSCRIPTION_INTERVAL); + + synchronizer = new SimpleBulletinBoardSynchronizer(); + synchronizer.init(localClient, remoteClient); + + semaphore = new Semaphore(0); + thrown = new LinkedList<>(); + + } + + private class SyncStatusCallback implements FutureCallback { + + @Override + public void onSuccess(SyncStatus result) { + + if (result == SyncStatus.SYNCHRONIZED){ + semaphore.release(); + } + + } + + @Override + public void onFailure(Throwable t) { + thrown.add(t); + semaphore.release(); + } + } + + private class MessageCountCallback implements FutureCallback { + + private int[] expectedCounts; + private int currentIteration; + + public MessageCountCallback(int[] expectedCounts) { + this.expectedCounts = expectedCounts; + this.currentIteration = 0; + } + + @Override + public void onSuccess(Integer result) { + + if (currentIteration < expectedCounts.length){ + if (result != expectedCounts[currentIteration]){ + onFailure(new AssertionError("Wrong message count. Expected " + expectedCounts[currentIteration] + " but received " + result)); + currentIteration = expectedCounts.length; + return; + } + } + + currentIteration++; + + if (currentIteration == expectedCounts.length) + semaphore.release(); + } + + @Override + public void onFailure(Throwable t) { + thrown.add(t); + semaphore.release(); + } + } + + @Test + public void testSync() throws SignatureException, CommunicationException, InterruptedException { + + final int BATCH_ID = 1; + + BulletinBoardMessage msg = messageGenerator.generateRandomMessage(signers, 10, 10); + + MessageID msgID = localClient.postMessage(msg); + + CompleteBatch completeBatch = messageGenerator.generateRandomBatch(signers[0],BATCH_ID,10,10,10); + + localClient.postBatch(completeBatch); + + synchronizer.subscribeToSyncStatus(new SyncStatusCallback()); + + int[] expectedCounts = {2,0}; + synchronizer.subscribeToRemainingMessagesCount(new MessageCountCallback(expectedCounts)); + + Thread t = new Thread(synchronizer); + t.run(); + + semaphore.acquire(); + + synchronizer.stop(); + t.join(); + + assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), thrown.size() == 0); + + List msgList = remoteClient.readMessages(MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) + .build()) + .build()); + + assertThat("Wrong number of messages returned.", msgList.size() == 1); + assertThat("Returned message is not equal to original one", messageComparator.compare(msgList.get(0),msg) == 0); + + CompleteBatch returnedBatch = remoteClient.readBatch(BatchSpecificationMessage.newBuilder() + .setSignerId(signerIDs[0]) + .setBatchId(BATCH_ID) + .build()); + + assertThat("Returned batch does not equal original one.", completeBatch.equals(returnedBatch)); + + } + + @After + public void close() { + + synchronizer.stop(); + localClient.close(); + remoteClient.close(); + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 6b2ef4f..301fc8e 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -6,7 +6,6 @@ import java.util.*; import com.google.protobuf.*; import com.google.protobuf.Timestamp; -import com.sun.org.apache.xpath.internal.operations.Bool; import meerkat.bulletinboard.*; import meerkat.bulletinboard.sqlserver.mappers.*; import static meerkat.bulletinboard.BulletinBoardConstants.*; @@ -17,7 +16,6 @@ import meerkat.comm.MessageOutputStream; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; @@ -29,7 +27,6 @@ import javax.sql.DataSource; import meerkat.util.BulletinBoardUtils; import meerkat.util.TimestampComparator; -import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index bef6d68..f68548e 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -247,12 +247,12 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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)," + + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE," + + " FOREIGN KEY (TagId) REFERENCES TagTable(TagId) ON DELETE CASCADE," + " UNIQUE (EntryNum, TagID))"); list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE," - + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE)"); list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)"); @@ -261,7 +261,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider + " UNIQUE(SignerId, BatchId, SerialNum))"); list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT," - + " FOREIGN KEY (TagId) REFERENCES TagTable(TagId))"); + + " FOREIGN KEY (TagId) REFERENCES TagTable(TagId) ON DELETE CASCADE)"); list.add("CREATE INDEX IF NOT EXISTS BatchIndex ON BatchTagTable(SignerId, BatchId)"); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java index 569d4ef..c25d737 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardSynchronizer.java @@ -16,8 +16,8 @@ public interface BulletinBoardSynchronizer extends Runnable { public enum SyncStatus{ SYNCHRONIZED, // No more messages to upload - PENDING, // Synchronizer is uploading data - SERVER_ERROR, // Synchronizer encountered an error while uploading + PENDING, // Synchronizer is querying for data to upload and uploading it as needed + SERVER_ERROR, // Synchronizer encountered an error while uploading, but will retry STOPPED // Stopped/Not started by user } diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java index dff562e..ea25200 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageGenerator.java @@ -1,13 +1,14 @@ package meerkat.util; import com.google.protobuf.ByteString; +import meerkat.bulletinboard.BatchDigitalSignature; +import meerkat.bulletinboard.CompleteBatch; import meerkat.crypto.DigitalSignature; import meerkat.protobuf.BulletinBoardAPI.*; import com.google.protobuf.Timestamp; import java.math.BigInteger; import java.security.SignatureException; -import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Random; @@ -28,10 +29,33 @@ public class BulletinBoardMessageGenerator { return (byte) random.nextInt(); } + private byte[] randomBytes(int length) { + + byte[] result = new byte[length]; + + for (int i = 0; i < length; i++) { + result[i] = randomByte(); + } + + return result; + } + private String randomString(){ return new BigInteger(130, random).toString(32); } + private List randomStrings(int length) { + + List result = new LinkedList<>(); + + for (int i = 0; i < length; i++) { + result.add(randomString()); + } + + return result; + + } + /** * Generates a complete instance of a BulletinBoardMessage * @param signers contains the (possibly multiple) credentials required to sign the message @@ -46,23 +70,16 @@ public class BulletinBoardMessageGenerator { // Generate random data. - byte[] data = new byte[dataSize]; - String[] newTags = new String[tagNumber]; - for (int i = 0; i < dataSize; i++) { - data[i] = randomByte(); - } - for (int i = 0; i < tagNumber; i++) { - newTags[i] = randomString(); - } + UnsignedBulletinBoardMessage unsignedMessage = UnsignedBulletinBoardMessage.newBuilder() - .setData(ByteString.copyFrom(data)) + .setData(ByteString.copyFrom(randomBytes(dataSize))) .setTimestamp(timestamp) .addAllTag(tags) - .addAllTag(Arrays.asList(newTags)) + .addAllTag(randomStrings(tagNumber)) .build(); BulletinBoardMessage.Builder messageBuilder = @@ -102,7 +119,6 @@ public class BulletinBoardMessageGenerator { * @param tagNumber is the number of tags to generate * @return a random, signed Bulletin Board Message containing random data, tags and timestamp */ - public BulletinBoardMessage generateRandomMessage(DigitalSignature[] signers, int dataSize, int tagNumber) throws SignatureException { @@ -115,4 +131,97 @@ public class BulletinBoardMessageGenerator { } + /** + * Generates a complete instance of a CompleteBatch + * @param signer contains the credentials required to sign the message + * @param batchId is the (per-signer) batch-ID + * @param timestamp is the time at which the message was generated + * @param dataCount is the number of Batch Data in the batch + * @param dataSize is the number of bytes per Batch Data + * @param tagCount is the number of tags + * @param tags contains a list of tags to be added (in addition to the random ones) + * @return a random, signed CompleteBatch containing random data and tags + * @throws SignatureException if an error occurs while signing the batch + */ + public CompleteBatch generateRandomBatch(BatchDigitalSignature signer, int batchId, Timestamp timestamp, int dataCount, int dataSize, int tagCount, List tags) throws SignatureException { + + CompleteBatch result = new CompleteBatch(BeginBatchMessage.newBuilder() + .setSignerId(signer.getSignerID()) + .setBatchId(batchId) + .addAllTag(tags) + .addAllTag(randomStrings(tagCount)) + .build()); + + List batchDataList = new LinkedList<>(); + + for (int i = 0 ; i < dataCount ; i++) { + batchDataList.add(BatchData.newBuilder() + .setData(ByteString.copyFrom(randomBytes(dataSize))) + .build()); + } + + result.appendBatchData(batchDataList); + + result.setTimestamp(timestamp); + + signer.updateContent(result); + + result.setSignature(signer.sign()); + + return result; + + } + + /** + * Generates a complete instance of a CompleteBatch + * @param signer contains the credentials required to sign the message + * @param batchId is the (per-signer) batch-ID + * @param timestamp is the time at which the message was generated + * @param dataCount is the number of Batch Data in the batch + * @param dataSize is the number of bytes per Batch Data + * @param tagCount is the number of tags + * @return a random, signed CompleteBatch containing random data and tags + * @throws SignatureException if an error occurs while signing the batch + */ + public CompleteBatch generateRandomBatch(BatchDigitalSignature signer, int batchId, Timestamp timestamp, int dataCount, int dataSize, int tagCount) throws SignatureException { + return generateRandomBatch(signer, batchId, timestamp, dataCount, dataSize, tagCount, new LinkedList()); + } + + + /** + * Generates a complete instance of a CompleteBatch + * @param signer contains the credentials required to sign the message + * @param batchId is the (per-signer) batch-ID + * @param dataCount is the number of Batch Data in the batch + * @param dataSize is the number of bytes per Batch Data + * @param tagCount is the number of tags + * @param tags contains a list of tags to be added (in addition to the random ones) + * @return a random, signed CompleteBatch containing random data, tags and timestamp + * @throws SignatureException if an error occurs while signing the batch + */ + public CompleteBatch generateRandomBatch(BatchDigitalSignature signer, int batchId, int dataCount, int dataSize, int tagCount, List tags) throws SignatureException { + + Timestamp timestamp = Timestamp.newBuilder() + .setSeconds(random.nextLong()) + .setNanos(random.nextInt()) + .build(); + + return generateRandomBatch(signer, batchId, timestamp, dataCount, dataSize, tagCount, tags); + + } + + /** + * Generates a complete instance of a CompleteBatch + * @param signer contains the credentials required to sign the message + * @param batchId is the (per-signer) batch-ID + * @param dataCount is the number of Batch Data in the batch + * @param dataSize is the number of bytes per Batch Data + * @param tagCount is the number of tags + * @return a random, signed CompleteBatch containing random data, tags and timestamp + * @throws SignatureException if an error occurs while signing the batch + */ + public CompleteBatch generateRandomBatch(BatchDigitalSignature signer, int batchId, int dataCount, int dataSize, int tagCount) throws SignatureException { + return generateRandomBatch(signer, batchId, dataCount, dataSize, tagCount, new LinkedList()); + } + } From e91a48b5e1d63c8e38a10fd9cf68607f5e2738e6 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Wed, 1 Jun 2016 22:46:51 +0300 Subject: [PATCH 058/106] Fixed a few bugs. Changed H2 Query Provider to run in-memory. --- .../LocalBulletinBoardClient.java | 2 +- .../SimpleBulletinBoardSynchronizer.java | 23 +++++++++++-------- .../BulletinBoardSynchronizerTest.java | 20 +++++++++++----- .../GenericSubscriptionClientTester.java | 6 +---- .../sqlserver/H2QueryProvider.java | 2 +- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index 109d5ed..8e2284c 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -500,7 +500,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo MessagePoster poster = new MessagePoster(msg); poster.call(); - digest.update(msg); + digest.update(msg.getMsg()); return digest.digestAsMessageID(); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index f7e9baa..97b6d01 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -26,8 +26,11 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private List> syncStatusCallbacks; private static final MessageFilterList EMPTY_FILTER = MessageFilterList.getDefaultInstance(); - private static final int SLEEP_INTERVAL = 10000; // 10 Seconds - private static final int WAIT_CAP = 300000; // 5 minutes wait before deciding that the sync has failed fatally + private static final int DEFAULT_SLEEP_INTERVAL = 10000; // 10 Seconds + private static final int DEFAULT_WAIT_CAP = 300000; // 5 minutes wait before deciding that the sync has failed fatally + + private final int SLEEP_INTERVAL; + private final int WAIT_CAP; private Semaphore semaphore; @@ -123,6 +126,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize if (result.size() == 0) { newStatus = SyncStatus.SYNCHRONIZED; + semaphore.release(); } else{ // Upload messages @@ -181,8 +185,14 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize } - public SimpleBulletinBoardSynchronizer() { + public SimpleBulletinBoardSynchronizer(int sleepInterval, int waitCap) { this.syncStatus = SyncStatus.STOPPED; + this.SLEEP_INTERVAL = sleepInterval; + this.WAIT_CAP = waitCap; + } + + public SimpleBulletinBoardSynchronizer() { + this(DEFAULT_SLEEP_INTERVAL, DEFAULT_WAIT_CAP); } private synchronized void updateSyncStatus(SyncStatus newStatus) { @@ -257,11 +267,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize do { - if (syncStatus == SyncStatus.PENDING || syncStatus == SyncStatus.SERVER_ERROR) { - - localClient.readMessages(EMPTY_FILTER, callback); - - } + localClient.readMessages(EMPTY_FILTER, callback); try { @@ -272,7 +278,6 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize // We expect an interruption when the upload will complete } - } while (syncStatus == SyncStatus.PENDING); // Database is synced. Wait for new data. diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java index a3ace28..1813641 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java @@ -42,6 +42,9 @@ public class BulletinBoardSynchronizerTest { private static final int THREAD_NUM = 3; private static final int SUBSCRIPTION_INTERVAL = 1000; + private static final int SYNC_SLEEP_INTERVAL = 100; + private static final int SYNC_WAIT_CAP = 200; + private DeletableSubscriptionBulletinBoardClient localClient; private AsyncBulletinBoardClient remoteClient; @@ -70,6 +73,7 @@ public class BulletinBoardSynchronizerTest { signerIDs = new ByteString[1]; signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); + signerIDs[0] = signers[0].getSignerID(); InputStream keyStream = BulletinBoardSynchronizerTest.class.getResourceAsStream(KEYFILE_EXAMPLE); char[] password = KEYFILE_PASSWORD1.toCharArray(); @@ -122,7 +126,7 @@ public class BulletinBoardSynchronizerTest { THREAD_NUM, SUBSCRIPTION_INTERVAL); - synchronizer = new SimpleBulletinBoardSynchronizer(); + synchronizer = new SimpleBulletinBoardSynchronizer(SYNC_SLEEP_INTERVAL, SYNC_WAIT_CAP); synchronizer.init(localClient, remoteClient); semaphore = new Semaphore(0); @@ -200,15 +204,19 @@ public class BulletinBoardSynchronizerTest { int[] expectedCounts = {2,0}; synchronizer.subscribeToRemainingMessagesCount(new MessageCountCallback(expectedCounts)); - Thread t = new Thread(synchronizer); - t.run(); + Thread syncThread = new Thread(synchronizer); + syncThread.start(); - semaphore.acquire(); + semaphore.acquire(2); synchronizer.stop(); - t.join(); + syncThread.join(); - assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), thrown.size() == 0); + if (thrown.size() > 0) { + for (Throwable t : thrown) + System.err.println(t.getMessage()); + assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), false); + } List msgList = remoteClient.readMessages(MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java index 4a5fe62..52da797 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java @@ -16,8 +16,6 @@ import java.security.cert.CertificateException; import java.util.*; import java.util.concurrent.Semaphore; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; /** @@ -187,10 +185,8 @@ public class GenericSubscriptionClientTester { public void subscriptionTest() throws SignatureException, CommunicationException { - final int FIRST_POST_ID = 201; - final int SECOND_POST_ID = 202; final String COMMON_TAG = "SUBSCRIPTION_TEST"; - + List tags = new LinkedList<>(); tags.add(COMMON_TAG); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index f68548e..55faa8f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -231,7 +231,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("org.h2.Driver"); - dataSource.setUrl("jdbc:h2:~/" + dbName); + dataSource.setUrl("jdbc:h2:mem:" + dbName); return dataSource; From e2f3dbe6b2f615012e3365839369cf0a1e6b3e33 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 2 Jun 2016 10:38:31 +0300 Subject: [PATCH 059/106] Fixed some more issues (most have to do with concurrency). Implemented close method for the SQLServer which renders it unusable until reinitialization. Added test for Synchronizer for the case when the remote server is unavailable (test passes). Still need to fix Batch digest and sign issue. --- .../LocalBulletinBoardClient.java | 7 +- .../SimpleBulletinBoardSynchronizer.java | 14 +++- .../BulletinBoardSynchronizerTest.java | 70 +++++++++++++++---- .../sqlserver/BulletinBoardSQLServer.java | 4 +- 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index 8e2284c..f944214 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -32,13 +32,12 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo private final DeletableBulletinBoardServer server; private final ListeningScheduledExecutorService executorService; private final BatchDigest digest; - private final int subsrciptionDelay; + private final long subsrciptionDelay; /** * Initializes an instance of the client * @param server an initialized Bulletin Board Server instance which will perform the actual processing of the requests * @param threadNum is the number of concurrent threads to allocate for the client - * @param subscriptionDelay is the required delay between subscription calls in milliseconds */ public LocalBulletinBoardClient(DeletableBulletinBoardServer server, int threadNum, int subscriptionDelay) { this.server = server; @@ -108,7 +107,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { - Futures.addCallback(executorService.schedule(new CompleteBatchPoster(completeBatch), subsrciptionDelay, TimeUnit.MILLISECONDS), callback); + Futures.addCallback(executorService.submit(new CompleteBatchPoster(completeBatch)), callback); digest.update(completeBatch); return digest.digestAsMessageID(); @@ -353,7 +352,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo filterList = filterBuilder.build(); // Reschedule job - Futures.addCallback(executorService.submit(new MessageReader(filterList)), this); + Futures.addCallback(executorService.schedule(new MessageReader(filterList), subsrciptionDelay, TimeUnit.MILLISECONDS), this); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index 97b6d01..7700fd6 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -10,6 +10,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; /** * Created by Arbel on 13/04/2016. @@ -20,6 +21,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private DeletableSubscriptionBulletinBoardClient localClient; private AsyncBulletinBoardClient remoteClient; + private AtomicBoolean running; private volatile SyncStatus syncStatus; private List> messageCountCallbacks; @@ -160,8 +162,6 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize } - localClient.deleteMessage(message.getEntryNum()); - } catch (CommunicationException e) { // This is an error with the local server // TODO: log @@ -189,6 +189,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize this.syncStatus = SyncStatus.STOPPED; this.SLEEP_INTERVAL = sleepInterval; this.WAIT_CAP = waitCap; + this.running = new AtomicBoolean(false); } public SimpleBulletinBoardSynchronizer() { @@ -197,6 +198,12 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private synchronized void updateSyncStatus(SyncStatus newStatus) { + if (!running.get()) { + + newStatus = SyncStatus.STOPPED; + + } + if (newStatus != syncStatus){ syncStatus = newStatus; @@ -258,7 +265,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize @Override public void run() { - if (syncStatus == SyncStatus.STOPPED) { + if (running.compareAndSet(false,true)){ updateSyncStatus(SyncStatus.PENDING); SyncCallback callback = new SyncCallback(); @@ -302,6 +309,7 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize @Override public void stop() { + running.set(false); updateSyncStatus(SyncStatus.STOPPED); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java index 1813641..d412502 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java @@ -14,19 +14,18 @@ import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.util.BulletinBoardMessageComparator; import meerkat.util.BulletinBoardMessageGenerator; import org.junit.*; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.io.IOException; import java.io.InputStream; import java.security.*; import java.security.cert.CertificateException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; @@ -38,12 +37,13 @@ public class BulletinBoardSynchronizerTest { private static final String REMOTE_SERVER_ADDRESS = "remoteDB"; private static final String LOCAL_SERVER_ADDRESS = "localDB"; + private static int testCount; private static final int THREAD_NUM = 3; private static final int SUBSCRIPTION_INTERVAL = 1000; - private static final int SYNC_SLEEP_INTERVAL = 100; - private static final int SYNC_WAIT_CAP = 200; + private static final int SYNC_SLEEP_INTERVAL = 500; + private static final int SYNC_WAIT_CAP = 1000; private DeletableSubscriptionBulletinBoardClient localClient; private AsyncBulletinBoardClient remoteClient; @@ -105,12 +105,14 @@ public class BulletinBoardSynchronizerTest { signerIDs[0] = signers[0].getSignerID(); + testCount = 0; + } @Before public void init() throws CommunicationException { - DeletableBulletinBoardServer remoteServer = new BulletinBoardSQLServer(new H2QueryProvider(REMOTE_SERVER_ADDRESS)); + DeletableBulletinBoardServer remoteServer = new BulletinBoardSQLServer(new H2QueryProvider(REMOTE_SERVER_ADDRESS + testCount)); remoteServer.init(REMOTE_SERVER_ADDRESS); remoteClient = new LocalBulletinBoardClient( @@ -118,7 +120,7 @@ public class BulletinBoardSynchronizerTest { THREAD_NUM, SUBSCRIPTION_INTERVAL); - DeletableBulletinBoardServer localServer = new BulletinBoardSQLServer(new H2QueryProvider(LOCAL_SERVER_ADDRESS)); + DeletableBulletinBoardServer localServer = new BulletinBoardSQLServer(new H2QueryProvider(LOCAL_SERVER_ADDRESS + testCount)); localServer.init(LOCAL_SERVER_ADDRESS); localClient = new LocalBulletinBoardClient( @@ -132,14 +134,24 @@ public class BulletinBoardSynchronizerTest { semaphore = new Semaphore(0); thrown = new LinkedList<>(); + testCount++; + } private class SyncStatusCallback implements FutureCallback { + private final SyncStatus statusToWaitFor; + private AtomicBoolean stillWaiting; + + public SyncStatusCallback(SyncStatus statusToWaitFor) { + this.statusToWaitFor = statusToWaitFor; + stillWaiting = new AtomicBoolean(true); + } + @Override public void onSuccess(SyncStatus result) { - if (result == SyncStatus.SYNCHRONIZED){ + if (result == statusToWaitFor && stillWaiting.compareAndSet(true, false)){ semaphore.release(); } @@ -148,7 +160,9 @@ public class BulletinBoardSynchronizerTest { @Override public void onFailure(Throwable t) { thrown.add(t); - semaphore.release(); + if (stillWaiting.compareAndSet(true,false)) { + semaphore.release(); + } } } @@ -199,7 +213,7 @@ public class BulletinBoardSynchronizerTest { localClient.postBatch(completeBatch); - synchronizer.subscribeToSyncStatus(new SyncStatusCallback()); + synchronizer.subscribeToSyncStatus(new SyncStatusCallback(SyncStatus.SYNCHRONIZED)); int[] expectedCounts = {2,0}; synchronizer.subscribeToRemainingMessagesCount(new MessageCountCallback(expectedCounts)); @@ -207,7 +221,9 @@ public class BulletinBoardSynchronizerTest { Thread syncThread = new Thread(synchronizer); syncThread.start(); - semaphore.acquire(2); + if (!semaphore.tryAcquire(2, 4000, TimeUnit.MILLISECONDS)) { + thrown.add(new TimeoutException("Timeout occurred while waiting for synchronizer to sync.")); + } synchronizer.stop(); syncThread.join(); @@ -237,6 +253,36 @@ public class BulletinBoardSynchronizerTest { } + @Test + public void testServerError() throws SignatureException, CommunicationException, InterruptedException { + + BulletinBoardMessage msg = messageGenerator.generateRandomMessage(signers, 10, 10); + + remoteClient.close(); + + synchronizer.subscribeToSyncStatus(new SyncStatusCallback(SyncStatus.SERVER_ERROR)); + + localClient.postMessage(msg); + + Thread thread = new Thread(synchronizer); + + thread.start(); + + if (!semaphore.tryAcquire(4000, TimeUnit.MILLISECONDS)) { + thrown.add(new TimeoutException("Timeout occurred while waiting for synchronizer to sync.")); + } + + synchronizer.stop(); + thread.join(); + + if (thrown.size() > 0) { + for (Throwable t : thrown) + System.err.println(t.getMessage()); + assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), false); + } + + } + @After public void close() { diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 301fc8e..d331c53 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1090,6 +1090,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override - public void close() {} + public void close() { + jdbcTemplate = null; + } } From fe209f6b5a0cd95d5b8fa451ecfc68deed18d073 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 2 Jun 2016 10:39:29 +0300 Subject: [PATCH 060/106] Removed default testing for the Bulletin Board Client. --- bulletin-board-client/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bulletin-board-client/build.gradle b/bulletin-board-client/build.gradle index 8fdeba0..03c395a 100644 --- a/bulletin-board-client/build.gradle +++ b/bulletin-board-client/build.gradle @@ -69,7 +69,7 @@ dependencies { test { exclude '**/*IntegrationTest*' - outputs.upToDateWhen { false } +// outputs.upToDateWhen { false } } task integrationTest(type: Test) { From 229cbfd48f8e19dc5ef33336f26208cbb8a9d607 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 2 Jun 2016 13:01:41 +0300 Subject: [PATCH 061/106] Fixed some subscription functionality of the CachedClient --- .../CachedBulletinBoardClient.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index ac61114..15beec7 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -5,6 +5,7 @@ import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.*; +import meerkat.util.BulletinBoardUtils; import java.util.List; @@ -30,13 +31,13 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien private class SubscriptionStoreCallback implements FutureCallback> { - private final FutureCallback callback; + private final FutureCallback> callback; public SubscriptionStoreCallback(){ callback = null; } - public SubscriptionStoreCallback(FutureCallback callback){ + public SubscriptionStoreCallback(FutureCallback> callback){ this.callback = callback; } @@ -44,7 +45,30 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien public void onSuccess(List result) { for (BulletinBoardMessage msg : result) { try { - localClient.postMessage(msg); + + if (msg.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)) { + + // This is a batch message: need to upload batch data as well as the message itself + ByteString signerID = msg.getSig(0).getSignerId(); + int batchID = Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(msg, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); + + BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder() + .setSignerId(signerID) + .setBatchId(batchID) + .setStartPosition(0) + .build(); + + CompleteBatch completeBatch = localClient.readBatch(batchSpecificationMessage); + + localClient.postBatch(completeBatch); + + } else { + + // This is a regular message: post it + localClient.postMessage(msg); + + } + } catch (CommunicationException ignored) { // TODO: log } @@ -346,16 +370,21 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien localClient.close(); remoteClient.close(); synchronizer.stop(); + try { + syncThread.join(); + } catch (InterruptedException e) { + //TODO: log interruption + } } @Override public void subscribe(MessageFilterList filterList, FutureCallback> callback) { - subscriber.subscribe(filterList, callback); + subscriber.subscribe(filterList, new SubscriptionStoreCallback(callback)); } @Override public void subscribe(MessageFilterList filterList, long startEntry, FutureCallback> callback) { - subscriber.subscribe(filterList, startEntry, callback); + subscriber.subscribe(filterList, startEntry, new SubscriptionStoreCallback(callback)); } } \ No newline at end of file From ffac7c1e3486291b6e0f36952696013f8cb09654 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Thu, 2 Jun 2016 14:48:48 +0300 Subject: [PATCH 062/106] Fixed all of Tal's remarks. Switched to using the predefined BoolValue Protobuf. --- .../SimpleBulletinBoardClient.java | 3 +- .../SingleServerBulletinBoardClient.java | 2 -- .../SingleServerGenericPostWorker.java | 5 +-- .../sqlserver/BulletinBoardSQLServer.java | 34 +++++++++---------- .../webapp/BulletinBoardWebApp.java | 9 ++--- ...BulletinBoardSQLServerIntegrationTest.java | 7 ++-- .../GenericBulletinBoardServerTest.java | 7 ++-- .../bulletinboard/BulletinBoardServer.java | 10 +++--- .../pollingstation/PollingStationScanner.java | 10 +++--- .../main/proto/meerkat/PollingStation.proto | 7 ---- .../src/main/proto/meerkat/comm.proto | 10 +----- .../PollingStationScannerWebApp.java | 23 ++++++------- .../PollingStationWebScanner.java | 16 +++------ .../PollingStationWebScannerTest.java | 23 +++++-------- 14 files changed, 69 insertions(+), 97 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 26b1e4e..74eacae 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -1,5 +1,6 @@ package meerkat.bulletinboard; +import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; import meerkat.comm.CommunicationException; import meerkat.crypto.Digest; @@ -70,7 +71,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ // Only consider valid responses if (response.getStatusInfo() == Response.Status.OK || response.getStatusInfo() == Response.Status.CREATED) { - response.readEntity(BoolMsg.class).getValue(); + response.readEntity(BoolValue.class).getValue(); } } } catch (Exception e) { // Occurs only when server replies with valid status but invalid data diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 34531cf..5edd079 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -7,12 +7,10 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.BulletinBoardClientParams; import meerkat.util.BulletinBoardUtils; -import javax.ws.rs.NotFoundException; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java index 2148801..08a66d1 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenericPostWorker.java @@ -1,5 +1,6 @@ package meerkat.bulletinboard.workers.singleserver; +import com.google.protobuf.BoolValue; import meerkat.bulletinboard.SingleServerWorker; import meerkat.comm.CommunicationException; import meerkat.protobuf.Comm.*; @@ -43,8 +44,8 @@ public class SingleServerGenericPostWorker extends SingleServerWorker lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); if (lengthResult.get(0) != message.getBatchLength()) { - return BoolMsg.newBuilder().setValue(false).build(); + return BoolValue.newBuilder().setValue(false).build(); } // Get Tags and add them to CompleteBatch @@ -813,7 +813,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // TODO: Actual verification // //signer.verify(completeBatch); // } catch (CertificateException | InvalidKeyException | SignatureException e) { -// return BoolMsg.newBuilder().setValue(false).build(); +// return BoolValue.newBuilder().setValue(false).build(); // } // Batch verified: finalize it @@ -849,7 +849,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Return TRUE - return BoolMsg.newBuilder().setValue(true).build(); + return BoolValue.newBuilder().setValue(true).build(); } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index f88d31f..aef820e 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -8,6 +8,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.StreamingOutput; +import com.google.protobuf.BoolValue; import meerkat.bulletinboard.BulletinBoardServer; import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; import meerkat.bulletinboard.sqlserver.H2QueryProvider; @@ -88,7 +89,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { + public BoolValue postMessage(BulletinBoardMessage msg) throws CommunicationException { init(); return bulletinBoard.postMessage(msg); } @@ -132,7 +133,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolMsg beginBatch(BeginBatchMessage message) { + public BoolValue beginBatch(BeginBatchMessage message) { try { init(); return bulletinBoard.beginBatch(message); @@ -147,7 +148,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolMsg postBatchMessage(BatchMessage batchMessage) { + public BoolValue postBatchMessage(BatchMessage batchMessage) { try { init(); return bulletinBoard.postBatchMessage(batchMessage); @@ -162,7 +163,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolMsg closeBatchMessage(CloseBatchMessage message) { + public BoolValue closeBatchMessage(CloseBatchMessage message) { try { init(); return bulletinBoard.closeBatchMessage(message); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java index a9be646..844a050 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/BulletinBoardSQLServerIntegrationTest.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard; +import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; import com.google.protobuf.TextFormat; @@ -61,7 +62,7 @@ public class BulletinBoardSQLServerIntegrationTest { WebTarget webTarget; Response response; - BoolMsg bool; + BoolValue bool; BulletinBoardMessage msg; @@ -95,7 +96,7 @@ public class BulletinBoardSQLServerIntegrationTest { response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); System.err.println(response); - bool = response.readEntity(BoolMsg.class); + bool = response.readEntity(BoolValue.class); assert bool.getValue(); msg = BulletinBoardMessage.newBuilder() @@ -114,7 +115,7 @@ public class BulletinBoardSQLServerIntegrationTest { response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF)); System.err.println(response); - bool = response.readEntity(BoolMsg.class); + bool = response.readEntity(BoolValue.class); assert bool.getValue(); // Test reading mechanism diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index e09f051..49c3050 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -17,6 +17,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.*; +import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; @@ -457,7 +458,7 @@ public class GenericBulletinBoardServerTest { .setSeconds(978325) .setNanos(8097234) .build()); - BoolMsg result; + BoolValue result; // Create data @@ -527,7 +528,7 @@ public class GenericBulletinBoardServerTest { .build()); int currentBatch = completeBatches.size(); - BoolMsg result; + BoolValue result; // Define batch data @@ -646,7 +647,7 @@ public class GenericBulletinBoardServerTest { BulletinBoardMessage newMessage = bulletinBoardMessageGenerator.generateRandomMessage(signers, timestamp, 10, 10); - BoolMsg result = bulletinBoardServer.postMessage(newMessage); + BoolValue result = bulletinBoardServer.postMessage(newMessage); assertThat("Failed to post message to BB Server", result.getValue(), is(true)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index abe4335..1507ab7 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -1,9 +1,9 @@ package meerkat.bulletinboard; +import com.google.protobuf.BoolValue; import meerkat.comm.CommunicationException; import meerkat.comm.MessageOutputStream; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Comm.*; import java.util.Collection; @@ -30,7 +30,7 @@ public interface BulletinBoardServer{ * @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; + public BoolValue postMessage(BulletinBoardMessage msg) throws CommunicationException; /** * Read all messages posted matching the given filter @@ -48,7 +48,7 @@ public interface BulletinBoardServer{ * 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; + public BoolValue beginBatch(BeginBatchMessage message) throws CommunicationException; /** * Posts a (part of a) batch message to the bulletin board @@ -60,7 +60,7 @@ public interface BulletinBoardServer{ * 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; + public BoolValue postBatchMessage(BatchMessage batchMessage) throws CommunicationException; /** * Attempts to stop and finalize a batch message @@ -69,7 +69,7 @@ public interface BulletinBoardServer{ * 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; + public BoolValue closeBatchMessage(CloseBatchMessage message) throws CommunicationException; /** * Reads a batch message from the server (starting with the supplied position) diff --git a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java index 9adc616..290d0ee 100644 --- a/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java +++ b/meerkat-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java @@ -1,7 +1,7 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; -import meerkat.protobuf.Comm.BoolMsg; +import com.google.protobuf.BoolValue; import meerkat.protobuf.PollingStation.*; /** * Created by Arbel on 05/05/2016. @@ -45,16 +45,16 @@ public interface PollingStationScanner { /** * Sends a scan to all subscribers * @param scannedData contains the scanned data - * @return a BoolMsg containing TRUE iff the scanned data has been sent to at least one subscriber + * @return a BoolValue containing TRUE iff the scanned data has been sent to at least one subscriber */ - public BoolMsg newScan(ScannedData scannedData); + public BoolValue newScan(ScannedData scannedData); /** * Notifies subscribers about an error that occurred during scan * @param errorMsg is the error that occurred - * @return a BoolMsg containing TRUE iff the error has been sent to at least one subscriber + * @return a BoolValue containing TRUE iff the error has been sent to at least one subscriber */ - public BoolMsg reportScanError(ErrorMsg errorMsg); + public BoolValue reportScanError(ErrorMsg errorMsg); } diff --git a/meerkat-common/src/main/proto/meerkat/PollingStation.proto b/meerkat-common/src/main/proto/meerkat/PollingStation.proto index 35dbd12..0cdc658 100644 --- a/meerkat-common/src/main/proto/meerkat/PollingStation.proto +++ b/meerkat-common/src/main/proto/meerkat/PollingStation.proto @@ -12,11 +12,4 @@ message ScannedData { // Container for error messages message ErrorMsg { string msg = 1; -} - -// Container for HTTP address -message HTTPAddress { - string hostname = 1; - int32 port = 2; - string address = 3; } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/comm.proto b/meerkat-common/src/main/proto/meerkat/comm.proto index 2f23678..6808288 100644 --- a/meerkat-common/src/main/proto/meerkat/comm.proto +++ b/meerkat-common/src/main/proto/meerkat/comm.proto @@ -10,12 +10,4 @@ message BroadcastMessage { bool is_private = 3; bytes payload = 5; -} - -message BoolMsg { - bool value = 1; -} - -message IntMsg { - int32 value = 1; -} +} \ No newline at end of file diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java index edebe33..327c774 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java @@ -5,7 +5,7 @@ package meerkat.pollingstation; */ import com.google.common.util.concurrent.FutureCallback; -import meerkat.protobuf.Comm; +import com.google.protobuf.BoolValue; import meerkat.protobuf.PollingStation; import javax.annotation.PostConstruct; @@ -16,7 +16,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import java.io.IOException; -import java.util.Iterator; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; @@ -32,14 +31,14 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc @Context ServletContext servletContext; - Iterator> callbacks; + Iterable> callbacks; /** * This method is called by the Jetty engine when instantiating the servlet */ @PostConstruct public void init() throws Exception{ - callbacks = ((PollingStationWebScanner.CallbackAccessor) servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME)).getCallbackIterator(); + callbacks = (Iterable>) servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME); } @POST @@ -47,18 +46,18 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public Comm.BoolMsg newScan(PollingStation.ScannedData scannedData) { + public BoolValue newScan(PollingStation.ScannedData scannedData) { boolean handled = false; - while (callbacks.hasNext()){ + for (FutureCallback callback : callbacks){ - callbacks.next().onSuccess(scannedData); + callback.onSuccess(scannedData); handled = true; } - return Comm.BoolMsg.newBuilder() + return BoolValue.newBuilder() .setValue(handled) .build(); @@ -69,18 +68,18 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public Comm.BoolMsg reportScanError(PollingStation.ErrorMsg errorMsg) { + public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg) { boolean handled = false; - while (callbacks.hasNext()){ + for (FutureCallback callback : callbacks){ - callbacks.next().onFailure(new IOException(errorMsg.getMsg())); + callback.onFailure(new IOException(errorMsg.getMsg())); handled = true; } - return Comm.BoolMsg.newBuilder() + return BoolValue.newBuilder() .setValue(handled) .build(); diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java index d7fc6a4..a4e290a 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java @@ -1,6 +1,5 @@ package meerkat.pollingstation; -import java.util.Iterator; import java.util.List; import java.util.LinkedList; @@ -8,7 +7,6 @@ import com.google.common.util.concurrent.FutureCallback; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.*; -import meerkat.protobuf.PollingStation.*; import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.server.ResourceConfig; @@ -26,14 +24,14 @@ public class PollingStationWebScanner implements PollingStationScanner.Consumer{ private final Server server; private final List> callbacks; - public PollingStationWebScanner(HTTPAddress address) { + public PollingStationWebScanner(int port, String subAddress) { callbacks = new LinkedList<>(); - server = new Server(address.getPort()); + server = new Server(port); - ServletContextHandler servletContextHandler = new ServletContextHandler(server, address.getAddress()); - servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, new CallbackAccessor()); + ServletContextHandler servletContextHandler = new ServletContextHandler(server, subAddress); + servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, (Iterable>) callbacks); ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class); resourceConfig.register(ProtobufMessageBodyReader.class); @@ -59,10 +57,4 @@ public class PollingStationWebScanner implements PollingStationScanner.Consumer{ callbacks.add(scanCallback); } - public class CallbackAccessor { - public Iterator> getCallbackIterator() { - return callbacks.iterator(); - } - } - } diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index 63cd8dd..7da106c 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -2,8 +2,6 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; -import com.sun.org.apache.regexp.internal.RE; -import meerkat.protobuf.PollingStation; import meerkat.protobuf.PollingStation.*; import meerkat.rest.Constants; @@ -18,12 +16,10 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; -import java.io.IOException; import java.util.concurrent.Semaphore; import static meerkat.pollingstation.PollingStationConstants.*; -import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; /** @@ -32,7 +28,9 @@ import static org.hamcrest.MatcherAssert.assertThat; public class PollingStationWebScannerTest { private PollingStationScanner.Consumer scanner; - private HTTPAddress httpAddress; + private static final String ADDRESS = "http://localhost"; + private static final String SUB_ADDRESS = ""; + private static final int PORT = 8080; private Semaphore semaphore; private Throwable thrown; @@ -86,12 +84,7 @@ public class PollingStationWebScannerTest { System.err.println("Setting up Scanner WebApp!"); - httpAddress = HTTPAddress.newBuilder() - .setPort(8080) - .setHostname("http://localhost") - .build(); - - scanner = new PollingStationWebScanner(httpAddress); + scanner = new PollingStationWebScanner(PORT, SUB_ADDRESS); semaphore = new Semaphore(0); thrown = null; @@ -110,8 +103,8 @@ public class PollingStationWebScannerTest { Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); - WebTarget webTarget = client.target(httpAddress.getHostname() + ":" + httpAddress.getPort()) - .path(httpAddress.getAddress()).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + WebTarget webTarget = client.target(ADDRESS + ":" + PORT) + .path(SUB_ADDRESS).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); byte[] data = {(byte) 1, (byte) 2}; @@ -136,8 +129,8 @@ public class PollingStationWebScannerTest { Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); - WebTarget webTarget = client.target(httpAddress.getHostname() + ":" + httpAddress.getPort()) - .path(httpAddress.getAddress()).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + WebTarget webTarget = client.target(ADDRESS + ":" + PORT) + .path(SUB_ADDRESS).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); ErrorMsg errorMsg = ErrorMsg.newBuilder() .setMsg("!Error Message!") From 76d3fdeac290254da0e8d249fb02acba1a7f28ff Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 7 Jun 2016 16:15:08 +0300 Subject: [PATCH 063/106] Fixed the Selector classes. Fixed the crypto classes to handle signatures as well. Some more other fixes --- .../src/main/proto/meerkat/voting.proto | 19 +++ .../controller/VotingBoothController.java | 7 +- .../voting/controller/VotingBoothImpl.java | 46 +++--- .../callbacks/ChannelChoiceCallback.java | 24 +-- .../callbacks/VoterCancelException.java | 8 + .../controller/callbacks/VotingCallback.java | 24 +-- .../controller/commands/ShutDownCommand.java | 10 -- .../controller/selector/QuestionSelector.java | 7 +- .../controller/selector/SelectionData.java | 7 - .../selector/SimpleCategoriesData.java | 97 ------------ .../SimpleListCategoriesSelector.java | 144 ++++++++---------- ...othEncryptor.java => VBCryptoManager.java} | 19 +-- .../voting/encryptor/VBCryptoManagerImpl.java | 67 ++++++++ .../voting/encryptor/VBEncryptorImpl.java | 14 -- .../voting/output/BallotOutputDevice.java | 2 +- .../output/SystemConsoleOutputDevice.java | 6 +- .../meerkat/voting/ui/SystemConsoleUI.java | 31 +++- .../java/meerkat/voting/ui/VotingBoothUI.java | 5 + 18 files changed, 259 insertions(+), 278 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java rename voting-booth/src/main/java/meerkat/voting/encryptor/{VotingBoothEncryptor.java => VBCryptoManager.java} (60%) create mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java delete mode 100644 voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 8ece676..6c0b1e2 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -71,6 +71,12 @@ message EncryptedBallot { RerandomizableEncryptedMessage data = 2; } +message SignedEncryptedBallot { + EncryptedBallot encrypted_ballot = 1; + bytes signer_id = 2; + Signature signature = 3; +} + message BallotSecrets { PlaintextBallot plaintext_ballot = 1; @@ -126,3 +132,16 @@ message ElectionParams { // Data required in order to access the Bulletin Board Servers BulletinBoardClientParams bulletinBoardClientParams = 8; } + +message Category { + repeated uint32 questionIndex = 1; +} + +message CategoryChooser { + repeated Category category = 1; +} + +message SimpleCategoriesSelectionData { + Category shared_defaults = 1; + repeated CategoryChooser categoryChooser = 2; +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index 057f13d..6b706f3 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -2,12 +2,11 @@ package meerkat.voting.controller; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.ui.VotingBoothUI; -import meerkat.voting.encryptor.VotingBoothEncryptor; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; -import java.util.ArrayList; import java.util.List; @@ -19,12 +18,12 @@ public interface VotingBoothController extends Runnable{ /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller * @param outputDevice the ballot output device. Naturally a printer and/or ethernet connection - * @param vbEncryptor the encryption module + * @param vbCrypto the crypto module * @param vbUI User interface in which the voter chooses his answers * @param vbStorageManager storage component for handling files and USB sticks */ public void init (BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, + VBCryptoManager vbCrypto, VotingBoothUI vbUI, StorageManager vbStorageManager); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index cd53f65..2d79d33 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,17 +1,19 @@ package meerkat.voting.controller; -import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.selector.QuestionSelector; -import meerkat.voting.encryptor.VotingBoothEncryptor; +import meerkat.voting.encryptor.VBCryptoManager; +import meerkat.voting.encryptor.VBCryptoManager.EncryptionAndSecrets; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import meerkat.voting.ui.VotingBoothUI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.security.SignatureException; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; @@ -21,7 +23,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class VotingBoothImpl implements VotingBoothController { private BallotOutputDevice outputDevice; - private VotingBoothEncryptor encryptor; + private VBCryptoManager crypto; private VotingBoothUI ui; private StorageManager storageManager; private List questionsForChoosingChannel; @@ -49,12 +51,12 @@ public class VotingBoothImpl implements VotingBoothController { @Override public void init(BallotOutputDevice outputDevice, - VotingBoothEncryptor vbEncryptor, + VBCryptoManager vbCrypto, VotingBoothUI vbUI, StorageManager vbStorageManager) { logger.info("init is called"); this.outputDevice = outputDevice; - this.encryptor = vbEncryptor; + this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; } @@ -105,7 +107,7 @@ public class VotingBoothImpl implements VotingBoothController { logger.info("callShutDown command has been called"); shutDownHasBeenCalled = true; queue.clear(); - queue.add(new ShutDownCommand()); + ui.callShutDown(); } private void handleSingleTask (ControllerCommand task) { @@ -138,14 +140,6 @@ public class VotingBoothImpl implements VotingBoothController { else if (task instanceof ReportErrorCommand) { doReportErrorAndForceRestart((ReportErrorCommand)task); } - else if (task instanceof ShutDownCommand) { - // wasShutDownCalled is now true. Do nothing. - // The program will not access the command queue anymore, and will exit normally - if (!wasShutDownCalled()) { - logger.warn("Received a ShutDownCommand command. At this point shutDownHasBeenCalled flag should have been True, but it's not..."); - shutDownHasBeenCalled = true; - } - } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); @@ -208,7 +202,7 @@ public class VotingBoothImpl implements VotingBoothController { state.stateIdentifier = VBState.ANSWER_QUESTIONS; List channelChoiceAnswers = task.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); - state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(channelChoiceAnswers); + state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } @@ -229,7 +223,7 @@ public class VotingBoothImpl implements VotingBoothController { state.currentBallotSerialNumber, this.queue)); outputDevice.commitToBallot(state.plaintextBallot, - state.encryptedBallot, + state.signedEncryptedBallot, new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { @@ -243,8 +237,14 @@ public class VotingBoothImpl implements VotingBoothController { .setSerialNumber(task.getBallotSerialNumber()) .addAllAnswers(task.getVotingAnswers()) .build(); - VotingBoothEncryptor.EncryptionAndSecrets encryptionAndSecrets = encryptor.encrypt(state.plaintextBallot); - state.encryptedBallot = encryptionAndSecrets.getEncryptedBallot(); + EncryptionAndSecrets encryptionAndSecrets = null; + try { + encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); + } + catch (SignatureException | IOException e) { + // TODO: handle exception + } + state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } @@ -287,20 +287,20 @@ public class VotingBoothImpl implements VotingBoothController { private class ControllerState { public VBState stateIdentifier; - public int channelIdentifier; + public byte[] channelIdentifier; public List channelSpecificQuestions; public PlaintextBallot plaintextBallot; - public EncryptedBallot encryptedBallot; + public SignedEncryptedBallot signedEncryptedBallot; public BallotSecrets secrets; public int lastRequestIdentifier; public long currentBallotSerialNumber; public ControllerState () { plaintextBallot = null; - encryptedBallot = null; + signedEncryptedBallot = null; secrets = null; lastRequestIdentifier = -1; - channelIdentifier = -1; + channelIdentifier = null; channelSpecificQuestions = null; currentBallotSerialNumber = 0; } @@ -311,7 +311,7 @@ public class VotingBoothImpl implements VotingBoothController { } public void clearCiphertext () { - encryptedBallot = null; + signedEncryptedBallot = null; secrets = null; } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index f6abd5c..ea8094c 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -23,21 +23,21 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onSuccess(List result) { - if (result.size() != 0) { - logger.debug("callback for channel choice returned success"); - enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); - } - else { - logger.debug("ChannelChoiceCallback got a cancellation response: " + result); - enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); - } + logger.debug("callback for channel choice returned success"); + enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { - logger.error("channel choice initiated a failure: " + t); - enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), - getBallotSerialNumber(), - SystemMessages.getUnsuccessfulChannelChoiceMessage())); + if (t instanceof VoterCancelException) { + logger.debug("ChannelChoiceCallback got a cancellation response"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("channel choice initiated a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulChannelChoiceMessage())); + } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java new file mode 100644 index 0000000..4c0d411 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java @@ -0,0 +1,8 @@ +package meerkat.voting.controller.callbacks; + +/** + * Created by hai on 06/06/16. + */ +public class VoterCancelException extends Exception{ + // +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 5317374..4b6f2f7 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -23,21 +23,21 @@ public class VotingCallback extends ControllerCallback> { @Override public void onSuccess(List result) { - if (result.size() != 0) { - logger.debug("callback for voting returned success"); - enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); - } - else { - logger.debug("VotingCallback got a cancellation response: " + result); - enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); - } + logger.debug("callback for voting returned success"); + enqueueCommand(new EncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { - logger.error("voting initiated a failure: " + t); - enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), - getBallotSerialNumber(), - SystemMessages.getUnsuccessfulVotingMessage())); + if (t instanceof VoterCancelException) { + logger.debug("VotingCallback got a cancellation response"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + logger.error("voting initiated a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getUnsuccessfulVotingMessage())); + } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java deleted file mode 100644 index ee3c0f2..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ShutDownCommand.java +++ /dev/null @@ -1,10 +0,0 @@ -package meerkat.voting.controller.commands; - -/** - * Created by hai on 11/04/16. - */ -public class ShutDownCommand extends ControllerCommand { - public ShutDownCommand() { - super(0, 0); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index e409e36..e9decae 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -8,11 +8,8 @@ import java.util.List; */ public interface QuestionSelector { - public void setAllBallotQuestions (List allBallotQuestions); + public byte[] getChannelIdentifier (List channelChoiceAnswers); - public void setSelectionData(SelectionData data); + public List selectQuestionsForVoter (byte[] channelIdentifier); - public int getChannelIdentifier (List channelChoiceAnswers); - - public List selectQuestionsForVoter (List channelChoiceAnswers); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java deleted file mode 100644 index 24a1125..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SelectionData.java +++ /dev/null @@ -1,7 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * Created by hai on 11/05/16. - */ -public class SelectionData { -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java deleted file mode 100644 index 544a86d..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleCategoriesData.java +++ /dev/null @@ -1,97 +0,0 @@ -package meerkat.voting.controller.selector; - -/** - * This class is the SelectionData used to initialize a SimpleListCategoriesSelector. - * It holds a table of question categories. - * Every answer in the channel choice phase dictates a category of questions to include in the ballot. - * This class is simply only the data class of these categories. - * Specifically the questionSelectionsByAnswer member is this categories table: - * questionSelectionsByAnswer[questionNumber][answerNumber] is an array of question indices to include in ballot - * whenever the voter answered answerNumber on question questionNumber in the channel choice phase. - * Also the sharedDefaults member is a category of question indices to include for EVERY voter, - * regardless of his channel choice answers - */ -public class SimpleCategoriesData extends SelectionData{ - - private int[] sharedDefaults; // a category of questions to include for every voter - // the categories - // first index is the question number, the second is the answer number. the value is an array of question indices in this category - private int[][][] questionSelectionsByAnswer; - private int maxQuestionNumber; - - public SimpleCategoriesData() { - sharedDefaults = new int[0]; - questionSelectionsByAnswer = new int[0][][]; - maxQuestionNumber = -1; - } - - public void setSharedDefaults(int[] sharedDefaultsIndices) { - this.sharedDefaults = sharedDefaultsIndices.clone(); - maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(sharedDefaultsIndices)); - } - - public int[] getSharedDefaults() { - return sharedDefaults; - } - - public void setItem(int questionNumber, int answerNumber, int[] questionIndices) { - if (questionNumber >= questionSelectionsByAnswer.length) { - int[][][] tmp = new int[questionNumber+1][][]; - System.arraycopy(questionSelectionsByAnswer, 0, tmp, 0, questionSelectionsByAnswer.length); - tmp[questionNumber] = new int[0][]; - questionSelectionsByAnswer = tmp; - } - - if (answerNumber >= questionSelectionsByAnswer[questionNumber].length) { - int[][] tmp = new int[answerNumber+1][]; - System.arraycopy(questionSelectionsByAnswer[questionNumber], 0, - tmp, 0, questionSelectionsByAnswer[questionNumber].length); - questionSelectionsByAnswer[questionNumber] = tmp; - } - - questionSelectionsByAnswer[questionNumber][answerNumber] = questionIndices.clone(); - maxQuestionNumber = Math.max(maxQuestionNumber, maxIntInArray(questionIndices)); - } - - public int[] getItem(int questionNumber, int answerNumber) { - return questionSelectionsByAnswer[questionNumber][answerNumber]; - } - - public int getMaxQuestionNumber() { - return maxQuestionNumber; - } - - - private static int maxIntInArray(int[] arr) { - int m = -1; - for (int i: arr) { - m = Math.max(i , m); - } - return m; - } - - public String toString () { - String s = "SimpleCategoriesData:\n"; - s += "shared : " + arrayToString(sharedDefaults) + "\n"; - s += "map : \n"; - for (int questionNumber = 0; questionNumber < questionSelectionsByAnswer.length; ++questionNumber) { - for (int answerNumber = 0; answerNumber < questionSelectionsByAnswer[questionNumber].length; ++answerNumber) { - s += "(" + questionNumber + ", " + answerNumber + ") -> " + - arrayToString(questionSelectionsByAnswer[questionNumber][answerNumber]) + "\n"; - } - } - return s; - } - - private String arrayToString (int[] a) { - if (a.length == 0) { - return "[]"; - } - String s = "[" + a[0]; - for (int i = 1; i < a.length; ++i) { - s += ", " + a[i]; - } - return s + "]"; - } - -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index d953246..6181f05 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -1,89 +1,89 @@ package meerkat.voting.controller.selector; -import meerkat.protobuf.Voting.BallotAnswer; -import meerkat.protobuf.Voting.BallotQuestion; +import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; +import java.lang.Math; /** * A simple implementation of a QuestionSelector. * This implementation simply regards every single answer in the channel choice phase as an identifier of a category * Every category is an array of ballot questions. - * Data of categories is initialized and stored by a SimpleCategoriesData object. + * Data of categories is initialized and stored by a SimpleCategoriesSelectionData protobuf. * After receiving the answers from a channel choice phase, this class simply gathers all the categories * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question * is included if its index appears in any chosen category, or in the default category shared by all voters) */ public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); - private BallotQuestion[] allBallotQuestions; - private SimpleCategoriesData selectionData; - private boolean[] isSelected; + + private final BallotQuestion[] allBallotQuestions; + private final int[] sharedDefaults; + private final int[][][] categoryChoosers; + + private final static byte QUESTION_SELECTED = (byte)1; + private final static byte QUESTION_NOT_SELECTED = (byte)0; - public SimpleListCategoriesSelector() { - this.allBallotQuestions = null; - this.selectionData = null; - } - @Override - public void setAllBallotQuestions(List allBallotQuestions) { - this.allBallotQuestions = (BallotQuestion[])allBallotQuestions.toArray(); - isSelected = new boolean[this.allBallotQuestions.length]; - assertDataValid(); - } - - @Override - public void setSelectionData(SelectionData data) { - if (! (data instanceof SimpleCategoriesData)) { - String errorMessage = "Initialization of SimpleListCategoriesSelector with wrong object type"; - logger.error(errorMessage); - throw new RuntimeException(errorMessage); + public SimpleListCategoriesSelector(List allBallotQuestions, SimpleCategoriesSelectionData data) { + this.allBallotQuestions = new BallotQuestion[allBallotQuestions.size()]; + allBallotQuestions.toArray(this.allBallotQuestions); + sharedDefaults = listToIntArray(data.getSharedDefaults().getQuestionIndexList()); + int[][][] selectionDataTmp = new int[data.getCategoryChooserList().size()][][]; + int channelChoiceQuestionNumber = 0; + for (CategoryChooser catChooser: data.getCategoryChooserList()) { + selectionDataTmp[channelChoiceQuestionNumber] = new int[catChooser.getCategoryList().size()][]; + int channelChoiceAnswerNumber = 0; + for (Category category: catChooser.getCategoryList()) { + selectionDataTmp[channelChoiceQuestionNumber][channelChoiceAnswerNumber] = listToIntArray(category.getQuestionIndexList()); + ++channelChoiceAnswerNumber; + } + ++channelChoiceQuestionNumber; } - this.selectionData = (SimpleCategoriesData)data; + categoryChoosers = selectionDataTmp; assertDataValid(); } private void assertDataValid () { - if (selectionData != null && allBallotQuestions != null) { - int questionsLength = allBallotQuestions.length; - int maxQuestionNumber = selectionData.getMaxQuestionNumber(); - if (maxQuestionNumber >= questionsLength) { - String errorMessage = "Selection data refers to question index " + maxQuestionNumber + " while we have only " + questionsLength + " questions totally"; - logger.error(errorMessage); - throw new IndexOutOfBoundsException(errorMessage); + int questionsLength = allBallotQuestions.length; + int maxQuestionIndex = -1; + for (int[][] categoryChooser: categoryChoosers) { + for (int[] category: categoryChooser) { + for (int index: category) { + maxQuestionIndex = Math.max(maxQuestionIndex, index); + } } } + if (maxQuestionIndex >= questionsLength) { + String errorMessage = "Selection data refers to question index " + maxQuestionIndex + " while we have only " + questionsLength + " questions totally"; + logger.error(errorMessage); + throw new IndexOutOfBoundsException(errorMessage); + } } + @Override - public int getChannelIdentifier(List channelChoiceAnswers) { - return 0; - } + public byte[] getChannelIdentifier(List channelChoiceAnswers) { + byte[] isSelected = new byte[allBallotQuestions.length]; + java.util.Arrays.fill(isSelected, QUESTION_NOT_SELECTED); - @Override - public List selectQuestionsForVoter(List channelChoiceAnswers) { - java.util.Arrays.fill(isSelected, false); - markSelected(selectionData.getSharedDefaults()); - markSelectionsOfVoterChannelChoice ((BallotAnswer[])channelChoiceAnswers.toArray()); - int[] questionIndices = extractSelectedIndices(); - List selectedQuestions = new ArrayList<>(); - for (int questionIndex: questionIndices) { - selectedQuestions.add(allBallotQuestions[questionIndex]); + for (int i: sharedDefaults) { + isSelected[i] = QUESTION_SELECTED; } - return selectedQuestions; - } - private void markSelectionsOfVoterChannelChoice(BallotAnswer[] channelChoiceAnswers) { - for (int q = 0; q < channelChoiceAnswers.length; ++q) { - BallotAnswer ballotAnswer = channelChoiceAnswers[q]; - assertAnswerLengthIsOne(ballotAnswer, q); - assertKeyInSelectionData(q, (int)ballotAnswer.getAnswer(0)); - markSelected(selectionData.getItem(q, (int)ballotAnswer.getAnswer(0))); + int channelChoiceQuestionNumber = 0; + for (BallotAnswer ballotAnswer: channelChoiceAnswers) { + assertAnswerLengthIsOne(ballotAnswer, channelChoiceQuestionNumber); + for (int i: categoryChoosers[channelChoiceQuestionNumber][(int)ballotAnswer.getAnswer(0)]) { + isSelected[i] = QUESTION_SELECTED; + } } + + return isSelected; } private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { @@ -98,35 +98,23 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } } - private void assertKeyInSelectionData(int questionNumber, int answerNumber) { - int[] questionListToAdd = selectionData.getItem(questionNumber, answerNumber); - if (null == questionListToAdd) { - String errorMessage = "SimpleListCategoriesSelector could not resolve answer number " + answerNumber + " for question number " + questionNumber; - logger.error(errorMessage); - throw new IllegalArgumentException(errorMessage); - } - } - - private void markSelected (int[] questionIndices) { - for (int i: questionIndices) { - isSelected[i] = true; - } - } - - private int[] extractSelectedIndices() { - int nSelected = 0; - for (boolean b: isSelected) { - if (b) { - nSelected++; + @Override + public List selectQuestionsForVoter(byte[] channelIdentifier) { + List selectedQuestions = new ArrayList<>(); + for (int i = 0; i < channelIdentifier.length; ++i) { + if (channelIdentifier[i] == QUESTION_SELECTED) { + selectedQuestions.add(allBallotQuestions[i]); } } - int[] res = new int[nSelected]; - int currIndex = 0; - for (int questionNumber = 0; questionNumber < isSelected.length; ++questionNumber) { - if (isSelected[questionNumber]) { - res[currIndex] = questionNumber; - currIndex++; - } + return selectedQuestions; + } + + private int[] listToIntArray(List l) { + int[] res = new int[l.size()]; + int index = 0; + for (Integer i: l) { + res[index] = i; + ++index; } return res; } diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java similarity index 60% rename from voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java rename to voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index e9a885f..e664607 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VotingBoothEncryptor.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -2,25 +2,27 @@ package meerkat.voting.encryptor; import meerkat.protobuf.Voting.*; +import java.io.IOException; +import java.security.SignatureException; + /** * An interface for the encryptor component of the voting booth */ -public interface VotingBoothEncryptor { - +public interface VBCryptoManager { /** * A simple class for pairing EncrypedBallot together with its matching BallotSecrets */ public class EncryptionAndSecrets { - private final EncryptedBallot encryptedBallot; + private final SignedEncryptedBallot signedEncryptedBallot; private final BallotSecrets secrets; - public EncryptionAndSecrets (EncryptedBallot encryptedBallot, BallotSecrets secrets) { - this.encryptedBallot = encryptedBallot; + public EncryptionAndSecrets (SignedEncryptedBallot encryptedBallot, BallotSecrets secrets) { + this.signedEncryptedBallot = encryptedBallot; this.secrets = secrets; } - public EncryptedBallot getEncryptedBallot () { - return encryptedBallot; + public SignedEncryptedBallot getSignedEncryptedBallot() { + return signedEncryptedBallot; } public BallotSecrets getSecrets() { @@ -34,8 +36,7 @@ public interface VotingBoothEncryptor { * @param plaintextBallot - all plaintext ballot info of the voter * @return an encryption of the ballot */ - public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot); + public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot) throws SignatureException, IOException; - //TODO: probably needs some key generation methods as well } diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java new file mode 100644 index 0000000..3f3a1b2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -0,0 +1,67 @@ +package meerkat.voting.encryptor; + +import meerkat.crypto.*; +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Voting.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.security.SignatureException; +import java.util.Random; + +/** + * Created by hai on 07/06/16. + */ +public class VBCryptoManagerImpl implements VBCryptoManager { + + protected final static Logger logger = LoggerFactory.getLogger(VBCryptoManagerImpl.class); + + private final Random random; + private final Encryption encryption; + private final DigitalSignature digitalSignature; + + + public VBCryptoManagerImpl (Random rand, Encryption encryption, DigitalSignature digitalSignature) { + this.random = rand; + this.encryption = encryption; + this.digitalSignature = digitalSignature; + } + + + @Override + public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) throws SignatureException, IOException { + + // TODO: do we seed the random here? + + try { + EncryptionRandomness encryptionRandomness = encryption.generateRandomness(random); + BallotSecrets secrets = BallotSecrets.newBuilder() + .setPlaintextBallot(plaintextBallot) + .setEncryptionRandomness(encryptionRandomness) + .build(); + RerandomizableEncryptedMessage encryptedMessage = encryption.encrypt(plaintextBallot, encryptionRandomness); + EncryptedBallot encBallot = EncryptedBallot.newBuilder() + .setSerialNumber(plaintextBallot.getSerialNumber()) + .setData(encryptedMessage) + .build(); + digitalSignature.updateContent(encBallot); + + SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() + .setEncryptedBallot(encBallot) + .setSignerId(digitalSignature.getSignerID()) + .setSignature(digitalSignature.sign()) + .build(); + + return new EncryptionAndSecrets(signedEncryptedBallot, secrets); + } + catch (IOException e) { + logger.error("encrypt: the encryption component has thrown an exception: " + e); + throw e; + } + catch (SignatureException e) { + logger.error("encrypt: the signature component has thrown an exception: " + e); + throw e; + } + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java deleted file mode 100644 index 51ffef0..0000000 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBEncryptorImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package meerkat.voting.encryptor; - -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 26/04/16. - */ -public class VBEncryptorImpl implements VotingBoothEncryptor { - - @Override - public EncryptionAndSecrets encrypt(PlaintextBallot plaintextBallot) { - throw new UnsupportedOperationException(); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 8d1f7f1..afbe223 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -15,7 +15,7 @@ public interface BallotOutputDevice { * @param callback - a callback object which expects no return value */ public void commitToBallot(PlaintextBallot plaintextBallot, - EncryptedBallot encryptedBallot, + SignedEncryptedBallot encryptedBallot, FutureCallback callback); /** diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index e1556d6..5d8446e 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -29,18 +29,18 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { @Override public void commitToBallot(PlaintextBallot plaintextBallot, - EncryptedBallot encryptedBallot, + SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("entered method commitToBallot"); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); - long encryptedSerialNumber = encryptedBallot.getSerialNumber(); + long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); if (plaintextSerialNumber != encryptedSerialNumber) { logger.error("plaintext and encryption serial numbers do not match!! plaintext# = " + plaintextSerialNumber + ", ciphertext# = " + encryptedSerialNumber); } - ByteString encryptedData = encryptedBallot.getData().getData(); + ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData(); System.out.println(bytesToString(encryptedData)); callback.onSuccess(null); } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 1ab1574..2f30a80 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -26,6 +26,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { private final int tickDurationInMillisec = 10; private Date startWaitingTime; + private volatile boolean shutDownHasBeenCalled; + + public SystemConsoleUI() { logger = LoggerFactory.getLogger(SystemConsoleUI.class); @@ -36,12 +39,15 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { startWaitingTime = null; Timer timer = new Timer(); timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + + shutDownHasBeenCalled = false; } + @Override public void run () { logger.info("entered the voting flow"); - while (true) { + while (! wasShutDownCalled()) { try { UICommand command = queue.take(); handleSingleCommand(command); @@ -53,6 +59,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + private void handleSingleCommand(UICommand command) { if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { @@ -142,6 +155,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } + catch (VoterCancelException e) { + command.getCallback().onFailure(e); + } catch (IOException e) { String errorMessage = "Channel choice failed due to IOException: " + e; logger.error (errorMessage); @@ -163,6 +179,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } + catch (VoterCancelException e) { + command.getCallback().onFailure(e); + } catch (IOException e) { String errorMessage = "Asking voting questions failed due to IOException: " + e; logger.error (errorMessage); @@ -320,7 +339,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private List askVoterForAnswers(List questions) throws IOException { + private List askVoterForAnswers(List questions) throws VoterCancelException, IOException { assertQuestionsAreValid (questions); @@ -335,7 +354,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { String s = readInputLine(); if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { - return null; + throw new VoterCancelException(); } else if (s.equals("back") || s.equals("b")) { --index; @@ -400,4 +419,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return data.toStringUtf8(); } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index 192dd1c..fccb28e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -16,6 +16,11 @@ public interface VotingBoothUI { AUDIT } + /** + * shut down the UI + */ + public void callShutDown(); + /** * Starts a new session for a voter. Presents whatever initial info is decided to show at the beginning * @param callback - a boolean future callback to return when done From 337a135151dfb75c2a9dc609d7986e4000e53e2b Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Wed, 15 Jun 2016 10:34:46 +0300 Subject: [PATCH 064/106] Started removing dependency on CompleteBatch. Tags of batches are now stored as a blob until the batch is complete. --- .../LocalBulletinBoardClient.java | 13 +-- .../SimpleBulletinBoardClient.java | 4 +- .../ThreadedBulletinBoardClient.java | 10 +-- .../MultiServerPostBatchWorker.java | 7 +- .../MultiServerReadBatchWorker.java | 6 +- .../sqlserver/BulletinBoardSQLServer.java | 90 ++++++------------- .../sqlserver/H2QueryProvider.java | 21 ++--- .../mappers/BeginBatchMessageMapper.java | 24 +++++ .../proto/meerkat/bulletin_board_server.proto | 9 -- .../AsyncBulletinBoardClient.java | 16 +++- .../meerkat/bulletinboard/BatchDigest.java | 20 ----- .../bulletinboard/BulletinBoardDigest.java | 42 +++++++++ .../bulletinboard/GenericBatchDigest.java | 61 ------------- .../GenericBulletinBoardDigest.java | 79 ++++++++++++++++ .../src/main/java/meerkat/crypto/Digest.java | 6 ++ .../meerkat/crypto/concrete/SHA256Digest.java | 1 + 16 files changed, 223 insertions(+), 186 deletions(-) create mode 100644 bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BeginBatchMessageMapper.java delete mode 100644 bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto delete mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardDigest.java delete mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java create mode 100644 meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index f944214..0bc03ee 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -31,7 +31,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo private final DeletableBulletinBoardServer server; private final ListeningScheduledExecutorService executorService; - private final BatchDigest digest; + private final BulletinBoardDigest digest; private final long subsrciptionDelay; /** @@ -42,7 +42,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public LocalBulletinBoardClient(DeletableBulletinBoardServer server, int threadNum, int subscriptionDelay) { this.server = server; this.executorService = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(threadNum)); - this.digest = new GenericBatchDigest(new SHA256Digest()); + this.digest = new GenericBulletinBoardDigest(new SHA256Digest()); this.subsrciptionDelay = subscriptionDelay; } @@ -74,9 +74,9 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo private class CompleteBatchPoster implements Callable { - private final CompleteBatch completeBatch; + private final BulletinBoardMessage completeBatch; - public CompleteBatchPoster(CompleteBatch completeBatch) { + public CompleteBatchPoster(BulletinBoardMessage completeBatch) { this.completeBatch = completeBatch; } @@ -84,7 +84,8 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override public Boolean call() throws CommunicationException { - server.beginBatch(completeBatch.getBeginBatchMessage()); + server.beginBatch(BeginBatchMessage.newBuilder().setSignerId(completeBatch.getSig(0)) + completeBatch.getBeginBatchMessage()); BatchMessage.Builder builder = BatchMessage.newBuilder() .setSignerId(completeBatch.getSignature().getSignerId()) @@ -105,7 +106,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { + public MessageID postBatch(ByteString signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback) { Futures.addCallback(executorService.submit(new CompleteBatchPoster(completeBatch)), callback); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 579ecf9..e8fcea0 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -28,7 +28,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ protected Client client; - protected BatchDigest digest; + protected BulletinBoardDigest digest; /** * Stores database locations and initializes the web Client @@ -44,7 +44,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ client.register(ProtobufMessageBodyWriter.class); // Wrap the Digest into a BatchDigest - digest = new GenericBatchDigest(new SHA256Digest()); + digest = new GenericBulletinBoardDigest(new SHA256Digest()); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 52e28e0..c53afe7 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -4,8 +4,6 @@ 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.*; @@ -31,7 +29,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple // Per-server clients private List clients; - private BatchDigest batchDigest; + private BulletinBoardDigest batchDigest; private final static int POST_MESSAGE_RETRY_NUM = 3; private final static int READ_MESSAGES_RETRY_NUM = 1; @@ -54,7 +52,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple super.init(clientParams); - batchDigest = new GenericBatchDigest(digest); + batchDigest = new GenericBulletinBoardDigest(digest); minAbsoluteRedundancy = (int) (clientParams.getMinRedundancy() * (float) clientParams.getBulletinBoardAddressCount()); @@ -100,7 +98,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { + public MessageID postBatch(BulletinBoardMessage completeBatch, FutureCallback callback) { // Create job MultiServerPostBatchWorker worker = @@ -213,7 +211,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { // Create job MultiServerReadBatchWorker worker = diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java index 1b1f3df..763485f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java @@ -3,16 +3,17 @@ package meerkat.bulletinboard.workers.multiserver; import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.CompleteBatch; import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker { +public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker { public MultiServerPostBatchWorker(List clients, - int minServers, CompleteBatch payload, int maxRetry, + int minServers, BulletinBoardMessage payload, int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); @@ -20,7 +21,7 @@ public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker { +public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { public MultiServerReadBatchWorker(List clients, int minServers, BatchSpecificationMessage payload, int maxRetry, - FutureCallback futureCallback) { + FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index d331c53..49ceb7b 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -13,6 +13,7 @@ import static meerkat.bulletinboard.BulletinBoardConstants.*; import meerkat.comm.CommunicationException; import meerkat.comm.MessageOutputStream; +import meerkat.crypto.DigitalSignature; import meerkat.crypto.concrete.ECDSASignature; import meerkat.crypto.concrete.SHA256Digest; @@ -136,9 +137,9 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER, Types.BLOB} ), - CONNECT_BATCH_TAG( - new String[] {"SignerId", "BatchId", "Tag"}, - new int[] {Types.BLOB, Types.INTEGER, Types.VARCHAR} + STORE_BATCH_TAGS( + new String[] {"SignerId", "BatchId", "Tags"}, + new int[] {Types.BLOB, Types.INTEGER, Types.BLOB} ), GET_BATCH_TAGS( @@ -326,8 +327,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ protected NamedParameterJdbcTemplate jdbcTemplate; - protected BatchDigest digest; - protected BatchDigitalSignature signer; + protected BulletinBoardDigest digest; + protected DigitalSignature signer; protected List trusteeSignatureVerificationArray; protected int minTrusteeSignatures; @@ -363,7 +364,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ public void init(String meerkatDB) throws CommunicationException { // TODO write signature reading part. - digest = new GenericBatchDigest(new SHA256Digest()); + digest = new GenericBulletinBoardDigest(new SHA256Digest()); signer = new GenericBatchDigitalSignature(new ECDSASignature()); jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); @@ -749,28 +750,15 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ return BoolMsg.newBuilder().setValue(false).build(); } - // Add new tags to table - ProtocolStringList tagList = message.getTagList(); - String[] tags = new String[tagList.size()]; - tags = tagList.toArray(tags); - try { - insertNewTags(tags); - } catch (SQLException e) { - throw new CommunicationException(e.getMessage()); - } + // Store tags + String sql = sqlQueryProvider.getSQLString(QueryType.STORE_BATCH_TAGS); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - // Connect tags - String sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_BATCH_TAG); - MapSqlParameterSource namedParameters[] = new MapSqlParameterSource[tags.length]; + namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(0),message.getSignerId().toByteArray()); + namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(1),message.getBatchId()); + namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(2),message.toByteArray()); - for (int i=0 ; i < tags.length ; i++) { - namedParameters[i] = new MapSqlParameterSource(); - namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(0),message.getSignerId().toByteArray()); - namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(1),message.getBatchId()); - namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(2),tags[i]); - } - - jdbcTemplate.batchUpdate(sql,namedParameters); + jdbcTemplate.update(sql,namedParameters); return BoolMsg.newBuilder().setValue(true).build(); @@ -832,18 +820,18 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId.toByteArray()); namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(1),batchId); - List tags = jdbcTemplate.query(sql, namedParameters, new StringMapper()); + List beginBatchMessages = jdbcTemplate.query(sql, namedParameters, new BeginBatchMessageMapper()); - CompleteBatch completeBatch = new CompleteBatch( - BeginBatchMessage.newBuilder() - .setSignerId(signerId) - .setBatchId(batchId) - .addAllTag(tags) - .build() - ); + if (beginBatchMessages == null || beginBatchMessages.size() <= 0 || beginBatchMessages.get(0) == null) { + return BoolMsg.newBuilder().setValue(false).build(); + } - // Add timestamp to CompleteBatch - completeBatch.setTimestamp(message.getTimestamp()); + UnsignedBulletinBoardMessage unsignedMessage = UnsignedBulletinBoardMessage.newBuilder() + .addAllTag(beginBatchMessages.get(0).getTagList()) + .addTag(BATCH_TAG) + .addTag(batchIdToTag(batchId)) + .setTimestamp(message.getTimestamp()) + .build(); // Add actual batch data to CompleteBatch @@ -854,36 +842,14 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),batchId); namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning - completeBatch.appendBatchData(jdbcTemplate.query(sql, namedParameters, new BatchDataMapper())); - - // Verify signature - - completeBatch.setSignature(message.getSig()); - -// try { -// TODO: Actual verification -// //signer.verify(completeBatch); -// } catch (CertificateException | InvalidKeyException | SignatureException e) { -// return BoolMsg.newBuilder().setValue(false).build(); -// } - - // Batch verified: finalize it - - // Calculate message ID - digest.reset(); - digest.update(completeBatch); - MessageID msgID = MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); + //TODO: Verification + // Will need to use the following to carry out the signature calculation: +// jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); // Create Bulletin Board message BulletinBoardMessage bulletinBoardMessage = BulletinBoardMessage.newBuilder() + .setMsg(unsignedMessage) .addSig(message.getSig()) - .setMsg(UnsignedBulletinBoardMessage.newBuilder() - .addAllTag(tags) - .addTag(BATCH_TAG) - .addTag(batchIdToTag(batchId)) - .setData(message.getSig().getSignerId()) - .setTimestamp(message.getTimestamp()) - .build()) .build(); // Post message without checking signature validity diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index 55faa8f..8d97690 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -134,18 +134,16 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider QueryType.CHECK_BATCH_LENGTH.getParamName(0), QueryType.CHECK_BATCH_LENGTH.getParamName(1)); - case CONNECT_BATCH_TAG: + case STORE_BATCH_TAGS: 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)); + "INSERT INTO BatchTagTable (SignerId, BatchId, TagId) VALUES (:{0}, :{1}, :{2})", + QueryType.STORE_BATCH_TAGS.getParamName(0), + QueryType.STORE_BATCH_TAGS.getParamName(1), + QueryType.STORE_BATCH_TAGS.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", + "SELECT Tags FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}", QueryType.GET_BATCH_TAGS.getParamName(0), QueryType.GET_BATCH_TAGS.getParamName(1)); @@ -255,15 +253,14 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE)"); 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 UNIQUE INDEX IF NOT EXISTS SignatureIndex 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) ON DELETE CASCADE)"); + list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, Tags BLOB)"); - list.add("CREATE INDEX IF NOT EXISTS BatchIndex ON BatchTagTable(SignerId, BatchId)"); + list.add("CREATE UNIQUE 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 diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BeginBatchMessageMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BeginBatchMessageMapper.java new file mode 100644 index 0000000..0f72ec9 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BeginBatchMessageMapper.java @@ -0,0 +1,24 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.InvalidProtocolBufferException; +import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Created by Arbel Deutsch Peled on 20-Dec-15. + */ +public class BeginBatchMessageMapper implements RowMapper { + + @Override + public BeginBatchMessage mapRow(ResultSet rs, int rowNum) throws SQLException { + try { + return BeginBatchMessage.newBuilder().mergeFrom(rs.getBytes(1)).build(); + } catch (InvalidProtocolBufferException e) { + return null; + } + } + +} diff --git a/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto b/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto deleted file mode 100644 index e31485b..0000000 --- a/bulletin-board-server/src/main/proto/meerkat/bulletin_board_server.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax = "proto3"; - -package meerkat; - -option java_package = "meerkat.protobuf"; - -message Boolean { - bool value = 1; -} \ No newline at end of file diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index d74c1ea..aa23417 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -21,11 +21,23 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { /** * Perform an end-to-end post of a signed batch message + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch * @param completeBatch contains all the data of the batch including the meta-data and the signature * @param callback is a class containing methods to handle the result of the operation * @return a unique identifier for the batch message */ - public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback); + + /** + * Perform an end-to-end post of a signed batch message + * @param signerId is the canonical form for the ID of the sender of this batch + * @param batchId is a unique (per signer) ID for this batch + * @param completeBatch contains all the data of the batch including the meta-data and the signature + * @param callback is a class containing methods to handle the result of the operation + * @return a unique identifier for the batch message + */ + public MessageID postBatch(ByteString signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback); /** * This message informs the server about the existence of a new batch message and supplies it with the tags associated with it @@ -94,7 +106,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param batchSpecificationMessage contains the data required to specify a single batch instance * @param callback is a callback class for handling the result of the operation */ - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback); + public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback); /** diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java deleted file mode 100644 index 6e30fe9..0000000 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BatchDigest.java +++ /dev/null @@ -1,20 +0,0 @@ -package meerkat.bulletinboard; - -import meerkat.crypto.Digest; -import meerkat.protobuf.BulletinBoardAPI.*; - -import java.util.List; - -/** - * Created by Arbel Deutsch Peled on 18-Dec-15. - * Extends the Digest interface with a method for digesting Batch messages - */ -public interface BatchDigest extends Digest { - - /** - * Update the digest with the batch message data (ignore the signature) - * @param completeBatch is the batch message that needs to be digested - */ - public void update(CompleteBatch completeBatch); - -} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardDigest.java new file mode 100644 index 0000000..0521d73 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardDigest.java @@ -0,0 +1,42 @@ +package meerkat.bulletinboard; + +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 18-Dec-15. + * Extends the Digest interface with a method for digesting Batch messages + */ +public interface BulletinBoardDigest extends Digest { + + /** + * Update the digest with the batch message data (ignore the signature) + * The digest only uses the part the signatures are computed on for this operation + * @param completeBatch is the batch message that needs to be digested + */ + public void updateCompleteBatch(BulletinBoardMessage completeBatch); + + /** + * Update the digest with a BulletinBoardMessage that contains only the metadata of a batch message + * The digest only uses the part the signatures are computed on for this operation + * This operation is necessary before beginning to digest the actual data + * @param batchStub contains the metadata + */ + public void updateBatchStub(BulletinBoardMessage batchStub); + + /** + * Update the digest with the batch message data (ignore the signature) + * @param completeBatch is the batch message that needs to be digested + */ + public void updateCompleteBatch(UnsignedBulletinBoardMessage completeBatch); + + /** + * Update the digest with a BulletinBoardMessage that contains only the metadata of a batch message + * This operation is necessary before beginning to digest the actual data + * @param batchStub contains the metadata + */ + public void updateBatchStub(UnsignedBulletinBoardMessage batchStub); + +} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java deleted file mode 100644 index 852bb24..0000000 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBatchDigest.java +++ /dev/null @@ -1,61 +0,0 @@ -package meerkat.bulletinboard; - -import com.google.protobuf.Message; -import meerkat.crypto.Digest; -import meerkat.protobuf.BulletinBoardAPI.MessageID; -import meerkat.protobuf.BulletinBoardAPI.BatchData; - -import java.util.List; - - -/** - * Created by Arbel Deutsch Peled on 19-Dec-15. - * Wrapper class for digesting Batches in a standardized way - */ -public class GenericBatchDigest implements BatchDigest{ - - private Digest digest; - - public GenericBatchDigest(Digest digest) { - this.digest = digest; - } - - @Override - public void update(CompleteBatch completeBatch) { - - update(completeBatch.getBeginBatchMessage()); - - for (BatchData batchData : completeBatch.getBatchDataList()) { - update(batchData); - } - - update(completeBatch.getTimestamp()); - - } - - @Override - public byte[] digest() { - return digest.digest(); - } - - @Override - public MessageID digestAsMessageID() { - return digest.digestAsMessageID(); - } - - @Override - public void update(Message msg) { - digest.update(msg); - } - - @Override - public void reset() { - digest.reset(); - } - - @Override - public GenericBatchDigest clone() throws CloneNotSupportedException{ - return new GenericBatchDigest(digest.clone()); - } - -} diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java new file mode 100644 index 0000000..cc912a7 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java @@ -0,0 +1,79 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.BytesValue; +import com.google.protobuf.Message; +import meerkat.crypto.Digest; +import meerkat.protobuf.BulletinBoardAPI; +import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.BulletinBoardAPI.MessageID; + + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + * Wrapper class for digesting Batches in a standardized way + */ +public class GenericBulletinBoardDigest implements BulletinBoardDigest { + + private Digest digest; + + public GenericBulletinBoardDigest(Digest digest) { + this.digest = digest; + } + + @Override + public byte[] digest() { + return digest.digest(); + } + + @Override + public MessageID digestAsMessageID() { + return digest.digestAsMessageID(); + } + + @Override + public void update(Message msg) { + digest.update(msg); + } + + @Override + public void update(byte[] data) { + digest.update(data); + } + + @Override + public void reset() { + digest.reset(); + } + + @Override + public GenericBulletinBoardDigest clone() throws CloneNotSupportedException{ + return new GenericBulletinBoardDigest(digest.clone()); + } + + @Override + public void updateCompleteBatch(BulletinBoardMessage completeBatch) { + updateCompleteBatch(completeBatch.getMsg()); + } + + @Override + public void updateBatchStub(BulletinBoardMessage batchStub) { + updateBatchStub(batchStub.getMsg()); + } + + @Override + public void updateCompleteBatch(UnsignedBulletinBoardMessage completeBatch) { + + // Digest just the signed part + UnsignedBulletinBoardMessage batchStub = completeBatch.toBuilder().clearData().build(); + updateBatchStub(batchStub); + + // Digest the data + update(completeBatch.getData().toByteArray()); + + } + + @Override + public void updateBatchStub(UnsignedBulletinBoardMessage batchStub) { + update(batchStub); + } +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java index b7d86dc..e5202d6 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -22,6 +22,12 @@ public interface Digest { */ public MessageID digestAsMessageID(); + /** + * Updates the digest using the given raw data + * @param data contains the raw data + */ + public void update (byte[] data); + /** * Updates the digest using the specified message (in serialized wire form) * diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index a7723ec..88f417c 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -80,6 +80,7 @@ public class SHA256Digest implements Digest { hash.update(msg.asReadOnlyByteBuffer()); } + @Override final public void update(byte[] msg) { hash.update(msg); } From 13f8948cfba9ebe914db1d1bf3cf06f85aeeb9fc Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 15 Jun 2016 19:32:05 +0300 Subject: [PATCH 065/106] change the output class to run as a thread. It is now runnable and has its own queue of (also new) OutputCommands, and its own shutdown flag. --- .../src/main/proto/meerkat/voting.proto | 3 +- .../java/meerkat/voting/ToyEncryption.java | 46 ++++ .../java/meerkat/voting/ToySignature.java | 82 +++++++ .../meerkat/voting/VotingBoothToyRun.java | 200 ++++++++++++++++++ .../voting/controller/VotingBoothImpl.java | 41 +++- .../callbacks/OutputDeviceCommitCallback.java | 34 +++ ...java => OutputDeviceFinalizeCallback.java} | 14 +- .../commands/ChooseFinalizeOptionCommand.java | 10 + .../voting/encryptor/VBCryptoManagerImpl.java | 1 - .../voting/output/BallotOutputDevice.java | 1 + .../output/SystemConsoleOutputDevice.java | 132 +++++++++--- .../outputcommands/AuditOutputCommand.java | 22 ++ .../outputcommands/CancelOutputCommand.java | 14 ++ .../outputcommands/CastOutputCommand.java | 14 ++ .../outputcommands/CommitOutputCommand.java | 29 +++ .../output/outputcommands/OutputCommand.java | 16 ++ .../meerkat/voting/ui/SystemConsoleUI.java | 2 +- 17 files changed, 609 insertions(+), 52 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/ToyEncryption.java create mode 100644 voting-booth/src/main/java/meerkat/voting/ToySignature.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java rename voting-booth/src/main/java/meerkat/voting/controller/callbacks/{OutputDeviceCallback.java => OutputDeviceFinalizeCallback.java} (58%) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 6c0b1e2..4edc9f5 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -73,8 +73,7 @@ message EncryptedBallot { message SignedEncryptedBallot { EncryptedBallot encrypted_ballot = 1; - bytes signer_id = 2; - Signature signature = 3; + Signature signature = 2; } message BallotSecrets { diff --git a/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java new file mode 100644 index 0000000..e0089c8 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToyEncryption.java @@ -0,0 +1,46 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Random; + +/** + * Created by hai on 07/06/16. + */ +public class ToyEncryption implements Encryption { + + @Override + public RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException { + ByteString cipher = ByteString.copyFromUtf8("Encryption(") + .concat(plaintext.toByteString()) + .concat(ByteString.copyFromUtf8(", Random(")) + .concat(rnd.getData()) + .concat(ByteString.copyFromUtf8("))")); + return RerandomizableEncryptedMessage.newBuilder() + .setData(cipher) + .build(); + } + + @Override + public RerandomizableEncryptedMessage rerandomize + (RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException { + throw new UnsupportedOperationException(); + } + + @Override + public EncryptionRandomness generateRandomness(Random rand) { + ByteBuffer b = ByteBuffer.allocate(4); + b.putInt(rand.nextInt()); + byte[] bArr = b.array(); + ByteString bs = ByteString.copyFrom(bArr); + return EncryptionRandomness.newBuilder() + .setData(bs) + .build(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ToySignature.java b/voting-booth/src/main/java/meerkat/voting/ToySignature.java new file mode 100644 index 0000000..e2473c9 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ToySignature.java @@ -0,0 +1,82 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.google.protobuf.Message; +import meerkat.crypto.DigitalSignature; +import meerkat.protobuf.Crypto.*; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +/** + * Created by hai on 07/06/16. + */ +public class ToySignature implements DigitalSignature { + + private final ByteString signerID; + private ByteString msgByteString; + + + public ToySignature(String signerID) { + this.signerID = ByteString.copyFromUtf8(signerID); + } + + @Override + public ByteString getSignerID() { + return signerID; + } + + @Override + public void updateContent(Message msg) throws SignatureException { + msgByteString = msg.toByteString(); + } + + @Override + public Signature sign() throws SignatureException { + ByteString signature = ByteString.copyFromUtf8("Signature(") + .concat(msgByteString) + .concat(ByteString.copyFromUtf8(")")); + return Signature.newBuilder() + .setType(SignatureType.ECDSA) + .setData(signature) + .setSignerId(getSignerID()) + .build(); + } + + + @Override + public void loadVerificationCertificates(InputStream certStream) throws CertificateException { + throw new UnsupportedOperationException(); + } + + @Override + public void clearVerificationCertificates() { + throw new UnsupportedOperationException(); + } + + @Override + public void initVerify(Signature sig) throws CertificateException, InvalidKeyException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean verify() { + throw new UnsupportedOperationException(); + } + + @Override + public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { + throw new UnsupportedOperationException(); + } + + + @Override + public void clearSigningKey() { + throw new UnsupportedOperationException(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java new file mode 100644 index 0000000..bf466f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -0,0 +1,200 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.*; +import meerkat.voting.controller.selector.SimpleListCategoriesSelector; +import meerkat.voting.output.*; +import meerkat.voting.storage.*; +import meerkat.voting.encryptor.*; +import meerkat.voting.ui.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by hai on 26/04/16. + */ +public class VotingBoothToyRun { + + public static void main(String[] args) { + + Random rand = new Random(); + Encryption enc = new ToyEncryption(); + DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); + + StorageManager storageManager = new StorageManagerMockup(); + SystemConsoleOutputDevice outputDevice = new SystemConsoleOutputDevice(); + VBCryptoManager cryptoManager = new VBCryptoManagerImpl(rand, enc, sig); + SystemConsoleUI ui = new SystemConsoleUI (); + + + VotingBoothImpl controller = new VotingBoothImpl(); + controller.init(outputDevice, cryptoManager, ui, storageManager); + + generateDemoQuestions(controller); + + // create threads + + + Thread controllerThread = new Thread(controller); + controllerThread.setName("Meerkat VB-Controller Thread"); + Thread uiThread = new Thread(ui); + uiThread.setName("Meerkat VB-UI Thread"); + Thread outputThread = new Thread(outputDevice); + uiThread.setName("Meerkat VB-Output Thread"); + + uiThread.start(); + controllerThread.start(); + outputThread.start(); + + } + + + private static void generateDemoQuestions(VotingBoothController controller) { + + List channelChoiceQuestions = generateCahnnelChoiceQuestions(); + controller.setBallotChannelChoiceQuestions(channelChoiceQuestions); + + List allBallotQuestions = generateBallotQuestions(); + controller.setBallotRaceQuestions(allBallotQuestions); + + SimpleCategoriesSelectionData selectionData = generateSelectionData(); + SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData); + controller.setChannelQuestionSelector(selector); + } + + + private static List generateCahnnelChoiceQuestions() { + ArrayList channelChoiceQuestions = new ArrayList(); + + String[] ans1 = {"Red", "Blue", "Green"}; + BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1); + channelChoiceQuestions.add(ccquestion1); + + String[] ans2 = {"Yes", "No"}; + BallotQuestion ccquestion2 = generateBallotQuestion("Are you a republican?", "Pick one answer", ans2); + channelChoiceQuestions.add(ccquestion2); + + return channelChoiceQuestions; + } + + + private static List generateBallotQuestions() { + ArrayList allBallotQuestions = new ArrayList(); + + String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"}; + allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1)); + + String[] answers2 = {"Miranda Kerr", "Doutzen Kroes", "Moran Atias", "Roslana Rodina", "Adriana Lima"}; + allBallotQuestions.add(generateBallotQuestion("question 2: Which model do you like", "Mark as many as you want", answers2)); + + allBallotQuestions.add(generateBallotQuestion("question 3. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 4. Asking something...", "Pick one answer", answers1)); + + String[] answers5 = {"Clint Eastwood", "Ninja", "Sonic", "Tai-chi", "Diablo", "Keanu"}; + allBallotQuestions.add(generateBallotQuestion("question 5: Good name for a cat", "Pick the best one", answers5)); + + allBallotQuestions.add(generateBallotQuestion("question 6. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 7. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 8. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 9. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 10. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 11. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 12. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 13. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 14. Asking something...", "Pick one answer", answers1)); + + return allBallotQuestions; + } + + + private static BallotQuestion generateBallotQuestion(String questionStr, String descriptionStr, String[] answers) { + UIElement question = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(questionStr)) + .build(); + + UIElement description = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(descriptionStr)) + .build(); + + BallotQuestion.Builder bqb = BallotQuestion.newBuilder(); + bqb.setIsMandatory(false); + bqb.setQuestion(question); + bqb.setDescription(description); + for (String answerStr : answers) { + UIElement answer = UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(stringToBytes(answerStr)) + .build(); + bqb.addAnswer(answer); + } + + return bqb.build(); + } + + + private static SimpleCategoriesSelectionData generateSelectionData() { + Category sharedDefaults = Category.newBuilder() + .addQuestionIndex(0) + .addQuestionIndex(5) + .addQuestionIndex(9) + .build(); + + Category cat00 = Category.newBuilder() + .addQuestionIndex(1) + .addQuestionIndex(4) + .addQuestionIndex(6) + .addQuestionIndex(7) + .build(); + + Category cat01 = Category.newBuilder() + .addQuestionIndex(2) + .addQuestionIndex(4) + .addQuestionIndex(8) + .build(); + + Category cat02 = Category.newBuilder() + .addQuestionIndex(3) + .addQuestionIndex(8) + .build(); + + Category cat10 = Category.newBuilder() + .addQuestionIndex(10) + .addQuestionIndex(11) + .build(); + + Category cat11 = Category.newBuilder() + .addQuestionIndex(12) + .addQuestionIndex(13) + .build(); + + CategoryChooser catChooser0 = CategoryChooser.newBuilder() + .addCategory(cat00) + .addCategory(cat01) + .addCategory(cat02) + .build(); + + CategoryChooser catChooser1 = CategoryChooser.newBuilder() + .addCategory(cat10) + .addCategory(cat11) + .build(); + + return SimpleCategoriesSelectionData.newBuilder() + .setSharedDefaults(sharedDefaults) + .addCategoryChooser(catChooser0) + .addCategoryChooser(catChooser1) + .build(); + + } + private static ByteString stringToBytes (String s) { + return ByteString.copyFromUtf8(s); + } + + +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 2d79d33..a9221bf 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -108,6 +108,7 @@ public class VotingBoothImpl implements VotingBoothController { shutDownHasBeenCalled = true; queue.clear(); ui.callShutDown(); + outputDevice.callShutDown(); } private void handleSingleTask (ControllerCommand task) { @@ -122,18 +123,21 @@ public class VotingBoothImpl implements VotingBoothController { if (task instanceof RestartVotingCommand) { doRestartVoting (); } - else if (task instanceof CastCommand) { - doFinalize(false); - } - else if (task instanceof AuditCommand) { - doFinalize(true); - } else if (task instanceof ChannelChoiceCommand) { doChooseChannel(); } else if (task instanceof ChannelDeterminedCommand) { doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); } + else if (task instanceof ChooseFinalizeOptionCommand) { + doChooseFinalizeOption(); + } + else if (task instanceof CastCommand) { + doFinalize(false); + } + else if (task instanceof AuditCommand) { + doFinalize(true); + } else if (task instanceof EncryptAndCommitBallotCommand) { doCommit ((EncryptAndCommitBallotCommand)task); } @@ -213,6 +217,19 @@ public class VotingBoothImpl implements VotingBoothController { } + private void doChooseFinalizeOption() { + if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) { + logger.debug("doChooseFinalizeOption"); + state.stateIdentifier = VBState.CAST_OR_AUDIT; + ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); + } + else { + logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); + // ignore this request + } + } private void doCommit (EncryptAndCommitBallotCommand task) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); @@ -224,7 +241,7 @@ public class VotingBoothImpl implements VotingBoothController { this.queue)); outputDevice.commitToBallot(state.plaintextBallot, state.signedEncryptedBallot, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { logger.debug("doCommit: current state is " + state.stateIdentifier); @@ -252,15 +269,17 @@ public class VotingBoothImpl implements VotingBoothController { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); if (auditRequested) { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.audit(state.secrets, - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } else { + ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), + new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); outputDevice.castBallot( - new OutputDeviceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } } else { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java new file mode 100644 index 0000000..a6eaadf --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -0,0 +1,34 @@ +package meerkat.voting.controller.callbacks; + +import meerkat.voting.controller.SystemMessages; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; +import meerkat.voting.controller.commands.ReportErrorCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class OutputDeviceCommitCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); + + public OutputDeviceCommitCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Void v) { + logger.debug("callback for output device commit success"); + enqueueCommand(new ChooseFinalizeOptionCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + + @Override + public void onFailure(Throwable t) { + logger.error("OutputDeviceCommitCallback got a failure: " + t); + enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), + getBallotSerialNumber(), + SystemMessages.getOutputDeviceFailureMessage())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java similarity index 58% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 2432f49..74a85e0 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -9,22 +9,24 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; -public class OutputDeviceCallback extends ControllerCallback { - protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCallback.class); +public class OutputDeviceFinalizeCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); - public OutputDeviceCallback(int requestId, - long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + public OutputDeviceFinalizeCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { super(requestId, ballotSerialNumber, controllerQueue); } @Override public void onSuccess(Void v) { + logger.debug("callback for output device finalize success"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } @Override public void onFailure(Throwable t) { - logger.error("WaitForFinishCallback got a failure: " + t); + logger.error("OutputDeviceFinalizeCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), SystemMessages.getOutputDeviceFailureMessage())); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java new file mode 100644 index 0000000..76b0e77 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +/** + * Created by hai on 11/04/16. + */ +public class ChooseFinalizeOptionCommand extends ControllerCommand { + public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 3f3a1b2..722c24e 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -49,7 +49,6 @@ public class VBCryptoManagerImpl implements VBCryptoManager { SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() .setEncryptedBallot(encBallot) - .setSignerId(digitalSignature.getSignerID()) .setSignature(digitalSignature.sign()) .build(); diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index afbe223..97fa7ed 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -37,4 +37,5 @@ public interface BallotOutputDevice { */ public void cancelBallot(FutureCallback callback); + public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 5d8446e..614dc40 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -4,22 +4,31 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.LinkedBlockingQueue; + /** * A toy OutputDevice class * outputs everything simply to the System console */ -public class SystemConsoleOutputDevice implements BallotOutputDevice { +public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; public SystemConsoleOutputDevice () { logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; } + /* * Returns the UTF8 decoding of byte-string data */ @@ -27,13 +36,69 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { return data.toStringUtf8(); } + @Override + public void run () { + logger.info("UI starts running"); + while (! wasShutDownCalled()) { + try { + OutputCommand command = queue.take(); + handleSingleCommand(command); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from command queue " + e); + } + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + + + private void handleSingleCommand(OutputCommand command) { + if (command instanceof CommitOutputCommand) { + doCommitToBallot((CommitOutputCommand)command); + } + else if (command instanceof AuditOutputCommand) { + doAudit((AuditOutputCommand)command); + } + else if (command instanceof CastOutputCommand) { + doCastBallot((CastOutputCommand)command); + } + else if (command instanceof CancelOutputCommand) { + doCancel((CancelOutputCommand)command); + } + else { + String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + @Override public void commitToBallot(PlaintextBallot plaintextBallot, SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { - logger.debug("entered method commitToBallot"); + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + PlaintextBallot plaintextBallot = command.getPlaintext(); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + System.out.println(plaintextBallot); + SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot(); long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); System.out.println("Commitment of Ballot #" + encryptedSerialNumber + " (ciphertext):"); if (plaintextSerialNumber != encryptedSerialNumber) { @@ -42,33 +107,52 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { } ByteString encryptedData = signedEncryptedBallot.getEncryptedBallot().getData().getData(); System.out.println(bytesToString(encryptedData)); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } + @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { - logger.debug("entered method audit"); + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); System.out.println("Auditing"); - printPlaintextBallot (ballotSecrets.getPlaintextBallot()); + BallotSecrets ballotSecrets = command.getBallotSecrets(); printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); printRandomnessGenerationProof (ballotSecrets.getProof()); - callback.onSuccess(null); + command.getCallback().onSuccess(null); } - private void printPlaintextBallot (PlaintextBallot plaintextBallot) { - long plaintextSerialNumber = plaintextBallot.getSerialNumber(); - System.out.println("Plaintext serial number = " + plaintextSerialNumber); - System.out.println("Answers = "); - for (BallotAnswer ballotAnswer : plaintextBallot.getAnswersList()) { - String printableAnswer = ""; - for (long n : ballotAnswer.getAnswerList()) { - printableAnswer += n + " "; - } - System.out.println(printableAnswer); - } + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); } + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + System.out.println("Ballot finalized for casting!"); + command.getCallback().onSuccess(null); + } + + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + System.out.println("Ballot cancelled!"); + command.getCallback().onSuccess(null); + } + + private void printEncryptionRandomness (EncryptionRandomness encryptionRandomness) { System.out.println("Encryption Randomness = "); ByteString data = encryptionRandomness.getData(); @@ -81,18 +165,4 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice { System.out.println(bytesToString(data)); } - - @Override - public void castBallot(FutureCallback callback) { - logger.debug("entered method castBallot"); - System.out.println("Ballot finalized for casting!"); - callback.onSuccess(null); - } - - @Override - public void cancelBallot(FutureCallback callback) { - logger.debug("entered method cancelBallot"); - System.out.println("Ballot cancelled!"); - callback.onSuccess(null); - } } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java new file mode 100644 index 0000000..2722326 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -0,0 +1,22 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class AuditOutputCommand extends OutputCommand { + + private final BallotSecrets ballotSecrets; + + public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { + super(callback); + this.ballotSecrets = ballotSecrets; + } + + public BallotSecrets getBallotSecrets() { + return ballotSecrets; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java new file mode 100644 index 0000000..0c360d2 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CancelOutputCommand extends OutputCommand { + + public CancelOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java new file mode 100644 index 0000000..af7ed30 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -0,0 +1,14 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CastOutputCommand extends OutputCommand { + + public CastOutputCommand(ControllerCallback callback) { + super(callback); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java new file mode 100644 index 0000000..dcd52f6 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -0,0 +1,29 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.ControllerCallback; + +/** + * Created by hai on 15/06/16. + */ +public class CommitOutputCommand extends OutputCommand { + + private final PlaintextBallot plaintextBallot; + private final SignedEncryptedBallot signedEncryptedBallot; + + public CommitOutputCommand(PlaintextBallot plaintextBallot, + SignedEncryptedBallot signedEncryptedBallot, + ControllerCallback callback) { + super(callback); + this.plaintextBallot = plaintextBallot; + this.signedEncryptedBallot = signedEncryptedBallot; + } + + public PlaintextBallot getPlaintext() { + return plaintextBallot; + } + + public SignedEncryptedBallot getSignedEncryptedBallot() { + return signedEncryptedBallot; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java new file mode 100644 index 0000000..8a7c322 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -0,0 +1,16 @@ +package meerkat.voting.output.outputcommands; + +import meerkat.voting.controller.callbacks.ControllerCallback; + +//TODO: make this class generic +public abstract class OutputCommand { + protected final ControllerCallback callback; + + protected OutputCommand(ControllerCallback callback) { + this.callback = callback; + } + + public ControllerCallback getCallback () { + return this.callback; + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index 2f30a80..bc3ac92 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -46,7 +46,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void run () { - logger.info("entered the voting flow"); + logger.info("UI starts running"); while (! wasShutDownCalled()) { try { UICommand command = queue.take(); From 1951db546dbb97e52f93a5d8e6c8d45acb3681fa Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 19 Jun 2016 22:00:43 +0300 Subject: [PATCH 066/106] Changed Bulletin Board Message payload to either data or message ID Added server-generated unique batch identifiers Changed Client-side interfaces Refactored Client-side code for new batch mechanisms Not tested on client-side yet --- .../bulletinboard/BatchDataContainer.java | 7 +- .../CachedBulletinBoardClient.java | 245 ++++++++----- .../CachedClientBatchIdentifier.java | 29 ++ .../LocalBulletinBoardClient.java | 330 ++++++++++-------- .../MultiServerBatchIdentifier.java | 27 ++ .../bulletinboard/MultiServerWorker.java | 10 +- .../SimpleBulletinBoardClient.java | 187 ++++++---- .../SimpleBulletinBoardSynchronizer.java | 15 +- .../SingleServerBatchIdentifier.java | 42 +++ .../SingleServerBulletinBoardClient.java | 220 ++++++++---- .../ThreadedBulletinBoardClient.java | 78 +++-- .../MultiServerBeginBatchWorker.java | 80 ++++- .../MultiServerCloseBatchWorker.java | 22 +- .../MultiServerGenericPostWorker.java | 7 +- .../MultiServerGenericReadWorker.java | 11 +- .../MultiServerGetRedundancyWorker.java | 7 +- .../MultiServerPostBatchDataWorker.java | 50 ++- .../MultiServerPostBatchWorker.java | 10 +- .../MultiServerReadBatchDataWorker.java | 29 ++ .../MultiServerReadBatchWorker.java | 8 +- .../SingleServerBeginBatchWorker.java | 37 +- .../SingleServerReadBatchWorker.java | 6 +- .../sqlserver/BulletinBoardSQLServer.java | 128 +++---- .../sqlserver/H2QueryProvider.java | 92 ++--- .../sqlserver/MySQLQueryProvider.java | 91 ++--- .../sqlserver/SQLiteQueryProvider.java | 93 ++--- .../sqlserver/mappers/MessageStubMapper.java | 2 +- .../webapp/BulletinBoardWebApp.java | 3 +- .../GenericBulletinBoardServerTest.java | 59 +--- .../H2BulletinBoardServerTest.java | 10 - .../MySQLBulletinBoardServerTest.java | 10 - .../SQLiteBulletinBoardServerTest.java | 25 +- .../AsyncBulletinBoardClient.java | 70 ++-- .../bulletinboard/BulletinBoardClient.java | 20 +- .../bulletinboard/BulletinBoardServer.java | 9 +- .../GenericBulletinBoardDigest.java | 2 +- .../GenericBulletinBoardSignature.java | 2 +- .../util/BulletinBoardMessageComparator.java | 10 +- .../java/meerkat/util/BulletinBoardUtils.java | 44 +-- .../main/proto/meerkat/BulletinBoardAPI.proto | 31 +- 40 files changed, 1274 insertions(+), 884 deletions(-) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedClientBatchIdentifier.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerBatchIdentifier.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBatchIdentifier.java create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java index 884aad7..1026529 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/BatchDataContainer.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard; import meerkat.protobuf.BulletinBoardAPI.BatchChunk; +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; import java.util.List; @@ -10,13 +11,11 @@ import java.util.List; */ public class BatchDataContainer { - public final byte[] signerId; - public final int batchId; + public final MultiServerBatchIdentifier batchId; public final List batchChunkList; public final int startPosition; - public BatchDataContainer(byte[] signerId, int batchId, List batchChunkList, int startPosition) { - this.signerId = signerId; + public BatchDataContainer(MultiServerBatchIdentifier batchId, List batchChunkList, int startPosition) { this.batchId = batchId; this.batchChunkList = batchChunkList; this.startPosition = startPosition; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index 3e1ed48..31521e1 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -1,11 +1,13 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm; +import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Voting.*; -import meerkat.util.BulletinBoardUtils; import java.util.List; @@ -46,21 +48,12 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien for (BulletinBoardMessage msg : result) { try { - if (msg.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)) { + if (msg.getMsg().getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { // This is a batch message: need to upload batch data as well as the message itself - ByteString signerID = msg.getSig(0).getSignerId(); - int batchID = Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(msg, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); + BulletinBoardMessage completeMessage = localClient.readBatchData(msg); - BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder() - .setSignerId(signerID) - .setBatchId(batchID) - .setStartPosition(0) - .build(); - - CompleteBatch completeBatch = localClient.readBatch(batchSpecificationMessage); - - localClient.postBatch(completeBatch); + localClient.postMessage(completeMessage); } else { @@ -126,12 +119,12 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public MessageID postBatch(final CompleteBatch completeBatch, final FutureCallback callback) { + public MessageID postAsBatch(final BulletinBoardMessage msg, final int chunkSize, final FutureCallback callback) { - return localClient.postBatch(completeBatch, new FutureCallback() { + return localClient.postAsBatch(msg, chunkSize, new FutureCallback() { @Override public void onSuccess(Boolean result) { - remoteClient.postBatch(completeBatch, callback); + remoteClient.postAsBatch(msg, chunkSize, callback); } @Override @@ -144,12 +137,31 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void beginBatch(final BeginBatchMessage beginBatchMessage, final FutureCallback callback) { + public void beginBatch(final Iterable tags, final FutureCallback callback) { + + localClient.beginBatch(tags, new FutureCallback() { + + private BatchIdentifier localIdentifier; - localClient.beginBatch(beginBatchMessage, new FutureCallback() { @Override - public void onSuccess(Boolean result) { - remoteClient.beginBatch(beginBatchMessage, callback); + public void onSuccess(BatchIdentifier result) { + + localIdentifier = result; + + remoteClient.beginBatch(tags, new FutureCallback() { + @Override + public void onSuccess(BatchIdentifier result) { + if (callback != null) + callback.onSuccess(new CachedClientBatchIdentifier(localIdentifier, result)); + } + + @Override + public void onFailure(Throwable t) { + if (callback != null) + callback.onFailure(t); + } + }); + } @Override @@ -162,13 +174,19 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void postBatchData(final byte[] signerId, final int batchId, final List batchChunkList, - final int startPosition, final FutureCallback callback) { + public void postBatchData(final BatchIdentifier batchIdentifier, final List batchChunkList, + final int startPosition, final FutureCallback callback) throws IllegalArgumentException{ - localClient.postBatchData(signerId, batchId, batchChunkList, startPosition, new FutureCallback() { + if (!(batchIdentifier instanceof CachedClientBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + final CachedClientBatchIdentifier identifier = (CachedClientBatchIdentifier) batchIdentifier; + + localClient.postBatchData(identifier.getLocalIdentifier(), batchChunkList, startPosition, new FutureCallback() { @Override public void onSuccess(Boolean result) { - remoteClient.postBatchData(signerId, batchId, batchChunkList, startPosition, callback); + remoteClient.postBatchData(identifier.getRemoteIdentifier(), batchChunkList, startPosition, callback); } @Override @@ -181,12 +199,19 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void postBatchData(final byte[] signerId, final int batchId, final List batchChunkList, final FutureCallback callback) { + public void postBatchData(final BatchIdentifier batchIdentifier, final List batchChunkList, final FutureCallback callback) + throws IllegalArgumentException{ - localClient.postBatchData(signerId, batchId, batchChunkList, new FutureCallback() { + if (!(batchIdentifier instanceof CachedClientBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + final CachedClientBatchIdentifier identifier = (CachedClientBatchIdentifier) batchIdentifier; + + localClient.postBatchData(identifier.getLocalIdentifier(), batchChunkList, new FutureCallback() { @Override public void onSuccess(Boolean result) { - remoteClient.postBatchData(signerId, batchId, batchChunkList, callback); + remoteClient.postBatchData(identifier.getRemoteIdentifier(), batchChunkList, callback); } @Override @@ -199,49 +224,21 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void postBatchData(final ByteString signerId, final int batchId, final List batchChunkList, - final int startPosition, final FutureCallback callback) { + public void closeBatch(final BatchIdentifier batchIdentifier, final Timestamp timestamp, final Iterable signatures, + final FutureCallback callback) { - localClient.postBatchData(signerId, batchId, batchChunkList, startPosition, new FutureCallback() { + if (!(batchIdentifier instanceof CachedClientBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + final CachedClientBatchIdentifier identifier = (CachedClientBatchIdentifier) batchIdentifier; + + localClient.closeBatch(identifier.getLocalIdentifier(), timestamp, signatures, new FutureCallback() { @Override public void onSuccess(Boolean result) { - remoteClient.postBatchData(signerId, batchId, batchChunkList, startPosition, callback); - } - @Override - public void onFailure(Throwable t) { - if (callback != null) - callback.onFailure(t); - } - }); + remoteClient.closeBatch(identifier.getRemoteIdentifier(), timestamp, signatures, callback); - } - - @Override - public void postBatchData(final ByteString signerId, final int batchId, final List batchChunkList, final FutureCallback callback) { - - localClient.postBatchData(signerId, batchId, batchChunkList, new FutureCallback() { - @Override - public void onSuccess(Boolean result) { - remoteClient.postBatchData(signerId, batchId, batchChunkList, callback); - } - - @Override - public void onFailure(Throwable t) { - if (callback != null) - callback.onFailure(t); - } - }); - - } - - @Override - public void closeBatch(final CloseBatchMessage closeBatchMessage, final FutureCallback callback) { - - localClient.closeBatch(closeBatchMessage, new FutureCallback() { - @Override - public void onSuccess(Boolean result) { - remoteClient.closeBatch(closeBatchMessage, callback); } @Override @@ -270,11 +267,12 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void readBatch(final BatchSpecificationMessage batchSpecificationMessage, final FutureCallback callback) { + public void readBatch(final MessageID msgID, final FutureCallback callback) { + + localClient.readBatch(msgID, new FutureCallback() { - localClient.readBatch(batchSpecificationMessage, new FutureCallback() { @Override - public void onSuccess(CompleteBatch result) { + public void onSuccess(BulletinBoardMessage result) { if (callback != null) callback.onSuccess(result); // Read from local client was successful } @@ -284,19 +282,61 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien // Read from local unsuccessful: try to read from remote - remoteClient.readBatch(batchSpecificationMessage, new FutureCallback() { + remoteClient.readBatch(msgID, new FutureCallback() { @Override - public void onSuccess(CompleteBatch result) { + public void onSuccess(BulletinBoardMessage result) { // Read from remote was successful: store in local and return result - localClient.postBatch(result, new FutureCallback() { - @Override - public void onSuccess(Boolean result) {} - @Override - public void onFailure(Throwable t) {} - }); + localClient.postMessage(result, null); + + if (callback != null) + callback.onSuccess(result); + + } + + @Override + public void onFailure(Throwable t) { + + // Read from remote was unsuccessful: report error + if (callback != null) + callback.onFailure(t); + + } + + }); + + } + + }); + + } + + @Override + public void readBatchData(final BulletinBoardMessage stub, final FutureCallback callback) throws IllegalArgumentException { + + localClient.readBatchData(stub, new FutureCallback() { + + @Override + public void onSuccess(BulletinBoardMessage result) { + if (callback != null) + callback.onSuccess(result); // Read from local client was successful + } + + @Override + public void onFailure(Throwable t) { + + // Read from local unsuccessful: try to read from remote + + remoteClient.readBatchData(stub, new FutureCallback() { + + @Override + public void onSuccess(BulletinBoardMessage result) { + + // Read from remote was successful: store in local and return result + + localClient.postMessage(result, null); if (callback != null) callback.onSuccess(result); @@ -340,8 +380,10 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { - return localClient.postBatch(completeBatch); + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException { + MessageID result = localClient.postAsBatch(msg, chunkSize); + remoteClient.postAsBatch(msg, chunkSize); + return result; } @Override @@ -356,8 +398,49 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { - return localClient.readBatch(batchSpecificationMessage); + public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { + + BulletinBoardMessage result = null; + try { + result = localClient.readBatch(msgID); + } catch (CommunicationException e) { + //TODO: log + } + + if (result == null){ + result = remoteClient.readBatch(msgID); + + if (result != null){ + localClient.postMessage(result); + } + + } + + return result; + + } + + @Override + public BulletinBoardMessage readBatchData(BulletinBoardMessage stub) throws CommunicationException, IllegalArgumentException { + + BulletinBoardMessage result = null; + try { + result = localClient.readBatchData(stub); + } catch (CommunicationException e) { + //TODO: log + } + + if (result == null){ + result = remoteClient.readBatchData(stub); + + if (result != null){ + localClient.postMessage(result); + } + + } + + return result; + } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedClientBatchIdentifier.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedClientBatchIdentifier.java new file mode 100644 index 0000000..322473d --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedClientBatchIdentifier.java @@ -0,0 +1,29 @@ +package meerkat.bulletinboard; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; + +import java.util.Arrays; + +/** + * Created by Arbel Deutsch Peled on 17-Jun-16. + */ +public final class CachedClientBatchIdentifier implements BatchIdentifier { + + // Per-server identifiers + private final BatchIdentifier localIdentifier; + private final BatchIdentifier remoteIdentifier; + + public CachedClientBatchIdentifier(BatchIdentifier localIdentifier, BatchIdentifier remoteIdentifier) { + this.localIdentifier = localIdentifier; + this.remoteIdentifier = remoteIdentifier; + } + + public BatchIdentifier getLocalIdentifier() { + return localIdentifier; + } + + public BatchIdentifier getRemoteIdentifier() { + return remoteIdentifier; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index d982dd2..f09b2d3 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -1,20 +1,21 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.*; -import com.google.protobuf.ByteString; +import com.google.protobuf.Int64Value; +import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; import meerkat.comm.MessageInputStream; import meerkat.comm.MessageInputStream.MessageInputStreamFactory; import meerkat.comm.MessageOutputStream; import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Voting.*; import meerkat.util.BulletinBoardUtils; import javax.ws.rs.NotFoundException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executors; @@ -74,48 +75,57 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo private class CompleteBatchPoster implements Callable { - private final BulletinBoardMessage completeBatch; + private final BulletinBoardMessage msg; + private final int chunkSize; - public CompleteBatchPoster(BulletinBoardMessage completeBatch) { - this.completeBatch = completeBatch; + public CompleteBatchPoster(BulletinBoardMessage msg, int chunkSize) { + this.msg = msg; + this.chunkSize = chunkSize; } @Override public Boolean call() throws CommunicationException { - server.beginBatch(BeginBatchMessage.newBuilder().setSignerId(completeBatch.getSig(0)) - completeBatch.getBeginBatchMessage()); + BeginBatchMessage beginBatchMessage = BeginBatchMessage.newBuilder() + .addAllTag(msg.getMsg().getTagList()) + .build(); + + Int64Value batchId = server.beginBatch(beginBatchMessage); BatchMessage.Builder builder = BatchMessage.newBuilder() - .setSignerId(completeBatch.getSignature().getSignerId()) - .setBatchId(completeBatch.getBeginBatchMessage().getBatchId()); + .setBatchId(batchId.getValue()); + + List batchChunkList = BulletinBoardUtils.breakToBatch(msg, chunkSize); int i=0; - for (BatchChunk data : completeBatch.getBatchDataList()){ + for (BatchChunk chunk : batchChunkList){ - server.postBatchMessage(builder.setSerialNum(i).setData(data).build()); + server.postBatchMessage(builder.setSerialNum(i).setData(chunk).build()); i++; } - return server.closeBatch(completeBatch.getCloseBatchMessage()).getValue(); + CloseBatchMessage closeBatchMessage = BulletinBoardUtils.generateCloseBatchMessage(batchId, batchChunkList.size(), msg); + + return server.closeBatch(closeBatchMessage).getValue(); } } @Override - public MessageID postBatch(ByteString signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback) { + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize, FutureCallback callback) { - Futures.addCallback(executorService.submit(new CompleteBatchPoster(completeBatch)), callback); + Futures.addCallback(executorService.submit(new CompleteBatchPoster(msg, chunkSize)), callback); - digest.update(completeBatch); + digest.reset(); + digest.update(msg); return digest.digestAsMessageID(); } - private class BatchBeginner implements Callable { + private class BatchBeginner implements Callable { private final BeginBatchMessage msg; @@ -125,26 +135,29 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override - public Boolean call() throws Exception { - return server.beginBatch(msg).getValue(); + public SingleServerBatchIdentifier call() throws Exception { + return new SingleServerBatchIdentifier(server.beginBatch(msg)); } } @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + public void beginBatch(Iterable tags, FutureCallback callback) { + + BeginBatchMessage beginBatchMessage = BeginBatchMessage.newBuilder() + .addAllTag(tags) + .build(); + Futures.addCallback(executorService.submit(new BatchBeginner(beginBatchMessage)), callback); } private class BatchDataPoster implements Callable { - private final ByteString signerId; - private final int batchId; + private final SingleServerBatchIdentifier batchId; private final List batchChunkList; private final int startPosition; - public BatchDataPoster(ByteString signerId, int batchId, List batchChunkList, int startPosition) { - this.signerId = signerId; + public BatchDataPoster(SingleServerBatchIdentifier batchId, List batchChunkList, int startPosition) { this.batchId = batchId; this.batchChunkList = batchChunkList; this.startPosition = startPosition; @@ -155,8 +168,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo public Boolean call() throws Exception { BatchMessage.Builder msgBuilder = BatchMessage.newBuilder() - .setSignerId(signerId) - .setBatchId(batchId); + .setBatchId(batchId.getBatchId().getValue()); int i = startPosition; for (BatchChunk data : batchChunkList){ @@ -178,24 +190,28 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, int startPosition, FutureCallback callback) { - postBatchData(ByteString.copyFrom(signerId), batchId, batchChunkList, startPosition, callback); + public void postBatchData(BatchIdentifier batchId, List batchChunkList, int startPosition, FutureCallback callback) + throws IllegalArgumentException{ + + // Cast identifier to usable form + + if (!(batchId instanceof SingleServerBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + SingleServerBatchIdentifier identifier = (SingleServerBatchIdentifier) batchId; + + // Add worker + + Futures.addCallback(executorService.submit(new BatchDataPoster(identifier, batchChunkList, startPosition)), callback); + } @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, FutureCallback callback) { - postBatchData(signerId, batchId, batchChunkList, 0, callback); + public void postBatchData(BatchIdentifier batchId, List batchChunkList, FutureCallback callback) throws IllegalArgumentException{ + postBatchData(batchId, batchChunkList, 0, callback); } - @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, int startPosition, FutureCallback callback) { - Futures.addCallback(executorService.submit(new BatchDataPoster(signerId, batchId, batchChunkList, startPosition)), callback); - } - - @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, FutureCallback callback) { - postBatchData(signerId, batchId, batchChunkList, 0, callback); - } private class BatchCloser implements Callable { @@ -214,8 +230,26 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + public void closeBatch(BatchIdentifier batchId, Timestamp timestamp, Iterable signatures, FutureCallback callback) { + + // Cast identifier to usable form + + if (!(batchId instanceof SingleServerBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + SingleServerBatchIdentifier identifier = (SingleServerBatchIdentifier) batchId; + + // Add worker + + CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() + .setBatchId(identifier.getBatchId().getValue()) + .setTimestamp(timestamp) + .addAllSig(signatures) + .build(); + Futures.addCallback(executorService.submit(new BatchCloser(closeBatchMessage)), callback); + } private class RedundancyGetter implements Callable { @@ -287,31 +321,6 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } - private class BatchDataReader implements Callable> { - - private final BatchSpecificationMessage batchSpecificationMessage; - - public BatchDataReader(BatchSpecificationMessage batchSpecificationMessage) { - this.batchSpecificationMessage = batchSpecificationMessage; - } - - @Override - public List call() throws Exception { - - ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); - MessageOutputStream outputStream = new MessageOutputStream<>(byteOutputStream); - server.readBatch(batchSpecificationMessage, outputStream); - - MessageInputStream inputStream = - MessageInputStreamFactory.createMessageInputStream( - new ByteArrayInputStream(byteOutputStream.toByteArray()), - BatchChunk.class); - - return inputStream.asList(); - - } - } - @Override public void readMessages(MessageFilterList filterList, FutureCallback> callback) { Futures.addCallback(executorService.submit(new MessageReader(filterList)), callback); @@ -387,83 +396,116 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo subscribe(filterList, 0, callback); } + private class BatchDataReader implements Callable> { + + private final MessageID msgID; + + public BatchDataReader(MessageID msgID) { + this.msgID = msgID; + } + + @Override + public List call() throws Exception { + + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(msgID) + .setStartPosition(0) + .build(); + + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + MessageOutputStream batchOutputStream = new MessageOutputStream<>(byteOutputStream); + server.readBatch(batchQuery,batchOutputStream); + + MessageInputStream inputStream = + MessageInputStreamFactory.createMessageInputStream( + new ByteArrayInputStream(byteOutputStream.toByteArray()), + BatchChunk.class); + + return inputStream.asList(); + + } + } + private class CompleteBatchReader implements Callable { - private final BatchSpecificationMessage batchSpecificationMessage; + private final MessageID msgID; - public CompleteBatchReader(BatchSpecificationMessage batchSpecificationMessage) { - this.batchSpecificationMessage = batchSpecificationMessage; + public CompleteBatchReader(MessageID msgID) { + this.msgID = msgID; } @Override public BulletinBoardMessage call() throws Exception { - final String[] TAGS_TO_REMOVE = {BulletinBoardConstants.BATCH_TAG, BulletinBoardConstants.BATCH_ID_TAG_PREFIX}; - - CompleteBatch completeBatch = new CompleteBatch(BeginBatchMessage.newBuilder() - .setSignerId(batchSpecificationMessage.getSignerId()) - .setBatchId(batchSpecificationMessage.getBatchId()) - .build()); - - ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); - MessageOutputStream batchOutputStream = new MessageOutputStream<>(byteOutputStream); - server.readBatch(batchSpecificationMessage,batchOutputStream); - - MessageInputStream batchInputStream = - MessageInputStreamFactory.createMessageInputStream( - new ByteArrayInputStream(byteOutputStream.toByteArray()), - BatchChunk.class); - - completeBatch.appendBatchData(batchInputStream.asList()); + // Read message stub MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_TAG) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + completeBatch.getBeginBatchMessage().getBatchId()) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(completeBatch.getBeginBatchMessage().getSignerId()) + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) .build()) .build(); - byteOutputStream = new ByteArrayOutputStream(); - MessageOutputStream messageOutputStream = new MessageOutputStream<>(byteOutputStream); - server.readMessages(filterList,messageOutputStream); + MessageReader messageReader = new MessageReader(filterList); + List bulletinBoardMessages = messageReader.call(); - MessageInputStream messageInputStream = - MessageInputStreamFactory.createMessageInputStream( - new ByteArrayInputStream(byteOutputStream.toByteArray()), - BulletinBoardMessage.class); - - if (!messageInputStream.isAvailable()) + if (bulletinBoardMessages.size() <= 0) { throw new NotFoundException("Batch does not exist"); + } - BulletinBoardMessage message = messageInputStream.readMessage(); + BulletinBoardMessage stub = bulletinBoardMessages.get(0); - completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() - .addAllTag(BulletinBoardUtils.removePrefixTags(message, Arrays.asList(TAGS_TO_REMOVE))) - .setSignerId(message.getSig(0).getSignerId()) - .setBatchId(Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX))) - .build()); + // Read data - completeBatch.setSignature(message.getSig(0)); - completeBatch.setTimestamp(message.getMsg().getTimestamp()); + BatchDataReader batchDataReader = new BatchDataReader(msgID); + List batchChunkList = batchDataReader.call(); - return completeBatch; + // Combine and return + + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); + + } + + } + + private class BatchDataCombiner implements Callable { + + private final BulletinBoardMessage stub; + + public BatchDataCombiner(BulletinBoardMessage stub) { + this.stub = stub; + } + + @Override + public BulletinBoardMessage call() throws Exception { + + MessageID msgID = MessageID.newBuilder().setID(stub.getMsg().getMsgId()).build(); + + BatchDataReader batchDataReader = new BatchDataReader(msgID); + + List batchChunkList = batchDataReader.call(); + + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); } } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { - Futures.addCallback(executorService.submit(new CompleteBatchReader(batchSpecificationMessage)), callback); + public void readBatch(MessageID msgID, FutureCallback callback) { + Futures.addCallback(executorService.submit(new CompleteBatchReader(msgID)), callback); + } + + @Override + public void readBatchData(BulletinBoardMessage stub, FutureCallback callback) throws IllegalArgumentException { + + if (stub.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID){ + throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); + } + + Futures.addCallback(executorService.submit(new BatchDataCombiner(stub)),callback); + } private class SyncQueryHandler implements Callable { @@ -506,12 +548,16 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException { - CompleteBatchPoster poster = new CompleteBatchPoster(completeBatch); - poster.call(); + CompleteBatchPoster poster = new CompleteBatchPoster(msg, chunkSize); + Boolean result = poster.call(); - digest.update(completeBatch); + if (!result) + throw new CommunicationException("Batch post failed"); + + digest.reset(); + digest.update(msg); return digest.digestAsMessageID(); } @@ -545,38 +591,48 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { + public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_TAG) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(batchSpecificationMessage.getSignerId()) + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) .build()) .build(); - BulletinBoardMessage batchMessage = readMessages(filterList).get(0); - - BatchDataReader batchDataReader = new BatchDataReader(batchSpecificationMessage); + CompleteBatchReader completeBatchReader = new CompleteBatchReader(msgID); try { - - List batchChunkList = batchDataReader.call(); - return new CompleteBatch(batchMessage, batchChunkList); - + return completeBatchReader.call(); } catch (Exception e) { - throw new CommunicationException("Error reading batch"); + throw new CommunicationException(e.getMessage() + " " + e.getMessage()); } } + @Override + public BulletinBoardMessage readBatchData(BulletinBoardMessage stub) throws CommunicationException, IllegalArgumentException { + + if (stub.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID){ + throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); + } + + MessageID msgID = MessageID.newBuilder().setID(stub.getMsg().getMsgId()).build(); + + BatchDataReader batchDataReader = new BatchDataReader(msgID); + + List batchChunkList = null; + + try { + batchChunkList = batchDataReader.call(); + } catch (Exception e) { + throw new CommunicationException(e.getCause() + " " + e.getMessage()); + } + + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); + + } + @Override public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException { return server.generateSyncQuery(generateSyncQueryParams); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerBatchIdentifier.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerBatchIdentifier.java new file mode 100644 index 0000000..4934ee6 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerBatchIdentifier.java @@ -0,0 +1,27 @@ +package meerkat.bulletinboard; + +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; + +import java.util.Arrays; + +/** + * Created by Arbel Deutsch Peled on 17-Jun-16. + */ +public final class MultiServerBatchIdentifier implements AsyncBulletinBoardClient.BatchIdentifier { + + // Per-server identifiers + private final Iterable identifiers; + + public MultiServerBatchIdentifier(Iterable identifiers) { + this.identifiers = identifiers; + } + + public MultiServerBatchIdentifier(BatchIdentifier[] identifiers) { + this.identifiers = Arrays.asList(identifiers); + } + + public Iterable getIdentifiers() { + return identifiers; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java index 60327fa..0073be2 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/MultiServerWorker.java @@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class MultiServerWorker extends BulletinClientWorker implements Runnable, FutureCallback{ - private final List clients; + protected final List clients; protected AtomicInteger minServers; // The minimal number of servers the job must be successful on for the job to be completed @@ -91,14 +91,6 @@ public abstract class MultiServerWorker extends BulletinClientWorker getClientIterator() { - return clients.iterator(); - } - protected int getClientNumber() { return clients.size(); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index a93a0d2..6250784 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -2,12 +2,15 @@ package meerkat.bulletinboard; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; +import com.google.protobuf.Int64Value; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; import meerkat.crypto.concrete.SHA256Digest; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Voting.*; import meerkat.rest.*; +import meerkat.util.BulletinBoardUtils; import java.util.List; @@ -86,47 +89,6 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build(); } - @Override - public MessageID postBatch(CompleteBatch completeBatch) throws CommunicationException { - - int pos = 0; - ByteString signerID = completeBatch.getSignature().getSignerId(); - int batchID = completeBatch.getBeginBatchMessage().getBatchId(); - - // Post message to all databases - - for (String db : meerkatDBs) { - - SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(db, completeBatch.getBeginBatchMessage(), 0); - - beginBatchWorker.call(); - - BatchMessage.Builder builder = BatchMessage.newBuilder().setSignerId(signerID).setBatchId(batchID); - - for (BatchChunk batchChunk : completeBatch.getBatchDataList()) { - - SingleServerPostBatchWorker postBatchWorker = - new SingleServerPostBatchWorker( - db, - builder.setData(batchChunk).setSerialNum(pos).build(), - 0); - - postBatchWorker.call(); - - pos++; - - } - - SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(db, completeBatch.getCloseBatchMessage(), 0); - - closeBatchWorker.call(); - - } - - digest.update(completeBatch); - return digest.digestAsMessageID(); - } - /** * Access each database and search for a given message ID * Return the number of databases in which the message was found @@ -173,17 +135,18 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ * @return the list of Bulletin Board messages that are returned from a server */ @Override - public List readMessages(MessageFilterList filterList) { + public List readMessages(MessageFilterList filterList) throws CommunicationException{ // Replace null filter list with blank one. if (filterList == null){ filterList = MessageFilterList.getDefaultInstance(); } + String exceptionString = ""; + for (String db : meerkatDBs) { try { - webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH); SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(db, filterList, 0); @@ -191,33 +154,92 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ return result; - } catch (Exception ignored) {} + } catch (Exception e) { + //TODO: log + exceptionString += e.getMessage() + "\n"; + } } - return null; + throw new CommunicationException("Could not find message in any DB. Errors follow:\n" + exceptionString); } @Override - public CompleteBatch readBatch(BatchSpecificationMessage batchSpecificationMessage) throws CommunicationException { + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException { - // Create job with no retries for retrieval of the Bulletin Board Message that defines the batch + List chunkList = BulletinBoardUtils.breakToBatch(msg, chunkSize); + + BeginBatchMessage beginBatchMessage = BulletinBoardUtils.generateBeginBatchMessage(msg); + + boolean posted = false; + + // Post message to all databases + + for (String db : meerkatDBs) { + + try { + + int pos = 0; + + SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(db, beginBatchMessage, 0); + + Int64Value batchId = beginBatchWorker.call(); + + BatchMessage.Builder builder = BatchMessage.newBuilder().setBatchId(batchId.getValue()); + + for (BatchChunk batchChunk : chunkList) { + + SingleServerPostBatchWorker postBatchWorker = + new SingleServerPostBatchWorker( + db, + builder.setData(batchChunk).setSerialNum(pos).build(), + 0); + + postBatchWorker.call(); + + pos++; + + } + + CloseBatchMessage closeBatchMessage = BulletinBoardUtils.generateCloseBatchMessage(batchId, chunkList.size(), msg); + + SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(db, closeBatchMessage, 0); + + closeBatchWorker.call(); + + posted = true; + + } catch(Exception ignored) {} + + } + + if (!posted){ + throw new CommunicationException("Could not post to any server"); + } + + digest.reset(); + digest.update(msg); + return digest.digestAsMessageID(); + + } + + @Override + public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_TAG) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(batchSpecificationMessage.getSignerId()) + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) .build()) .build(); + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(msgID) + .setStartPosition(0) + .build(); + + String exceptionString = ""; + for (String db : meerkatDBs) { try { @@ -228,20 +250,57 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ if (messages == null || messages.size() < 1) continue; - BulletinBoardMessage batchMessage = messages.get(0); + BulletinBoardMessage stub = messages.get(0); - SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(db, batchSpecificationMessage, 0); + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(db, batchQuery, 0); List batchChunkList = batchWorker.call(); - CompleteBatch result = new CompleteBatch(batchMessage, batchChunkList); + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); - return result; - - } catch (Exception ignored) {} + } catch (Exception e) { + //TODO: log + exceptionString += e.getMessage() + "\n"; + } } - return null; + throw new CommunicationException("Could not find message in any DB. Errors follow:\n" + exceptionString); + + } + + @Override + public BulletinBoardMessage readBatchData(BulletinBoardMessage stub) throws CommunicationException, IllegalArgumentException { + + if (stub.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID){ + throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); + } + + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(MessageID.newBuilder() + .setID(stub.getMsg().getMsgId()) + .build()) + .setStartPosition(0) + .build(); + + String exceptionString = ""; + + for (String db : meerkatDBs) { + + try { + + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(db, batchQuery, 0); + + List batchChunkList = batchWorker.call(); + + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); + + } catch (Exception e) { + //TODO: log + exceptionString += e.getMessage() + "\n"; + } + } + + throw new CommunicationException("Could not find message in any DB. Errors follow:\n" + exceptionString); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index 7700fd6..e8abf6b 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -137,22 +137,13 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize try { - if (message.getMsg().getTagList().contains(BulletinBoardConstants.BATCH_TAG)) { + if (message.getMsg().getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { // This is a batch message: need to upload batch data as well as the message itself - ByteString signerID = message.getSig(0).getSignerId(); - int batchID = Integer.parseInt(BulletinBoardUtils.findTagWithPrefix(message, BulletinBoardConstants.BATCH_ID_TAG_PREFIX)); - BatchSpecificationMessage batchSpecificationMessage = BatchSpecificationMessage.newBuilder() - .setSignerId(signerID) - .setBatchId(batchID) - .setStartPosition(0) - .build(); + BulletinBoardMessage completeMsg = localClient.readBatchData(message); - - CompleteBatch completeBatch = localClient.readBatch(batchSpecificationMessage); - - remoteClient.postBatch(completeBatch, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); + remoteClient.postMessage(completeMsg, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); } else { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBatchIdentifier.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBatchIdentifier.java new file mode 100644 index 0000000..9c4ad40 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBatchIdentifier.java @@ -0,0 +1,42 @@ +package meerkat.bulletinboard; + +import com.google.protobuf.Int64Value; + +/** + * Created by Arbel Deutsch Peled on 16-Jun-16. + * Single-server implementation of the BatchIdentifier interface + */ +final class SingleServerBatchIdentifier implements AsyncBulletinBoardClient.BatchIdentifier { + + private final Int64Value batchId; + + private int length; + + public SingleServerBatchIdentifier(Int64Value batchId) { + this.batchId = batchId; + length = 0; + } + + public SingleServerBatchIdentifier(long batchId) { + this(Int64Value.newBuilder().setValue(batchId).build()); + } + + public Int64Value getBatchId() { + return batchId; + } + + /** + * Overrides the existing length with the new one only if the new length is longer + * @param newLength + */ + public void setLength(int newLength) { + if (newLength > length) { + length = newLength; + } + } + + public int getLength() { + return length; + } + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 6ef013f..b985a8a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -4,11 +4,15 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import com.google.protobuf.ByteString; +import com.google.protobuf.Int64Value; +import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.BulletinBoardClientParams; +import meerkat.util.BulletinBoardUtils; +import java.lang.Iterable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -124,14 +128,14 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i * It reports success back to the user only if all of the batch-data were successfully posted * If any batch-data fails to post: this callback reports failure */ - class PostBatchDataListCallback implements FutureCallback { + class PostBatchChunkListCallback implements FutureCallback { private final FutureCallback callback; private AtomicInteger batchDataRemaining; private AtomicBoolean aggregatedResult; - public PostBatchDataListCallback(int batchDataLength, FutureCallback callback) { + public PostBatchChunkListCallback(int batchDataLength, FutureCallback callback) { this.callback = callback; this.batchDataRemaining = new AtomicInteger(batchDataLength); @@ -169,15 +173,15 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i */ class CompleteBatchReadCallback { - private final FutureCallback callback; + private final FutureCallback callback; private List batchChunkList; - private BulletinBoardMessage batchMessage; + private BulletinBoardMessage stub; private AtomicInteger remainingQueries; private AtomicBoolean failed; - public CompleteBatchReadCallback(FutureCallback callback) { + public CompleteBatchReadCallback(FutureCallback callback) { this.callback = callback; @@ -188,14 +192,10 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i protected void combineAndReturn() { - final String[] prefixes = { - BulletinBoardConstants.BATCH_ID_TAG_PREFIX, - BulletinBoardConstants.BATCH_TAG}; - if (remainingQueries.decrementAndGet() == 0){ if (callback != null) - callback.onSuccess(new CompleteBatch(batchMessage, batchChunkList)); + callback.onSuccess(BulletinBoardUtils.gatherBatch(stub, batchChunkList)); } } @@ -241,7 +241,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i return; } - batchMessage = result.get(0); + stub = result.get(0); combineAndReturn(); } @@ -367,18 +367,22 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i private class PostBatchDataCallback implements FutureCallback { - private final CompleteBatch completeBatch; + private final BulletinBoardMessage msg; + private final BatchIdentifier identifier; private final FutureCallback callback; - public PostBatchDataCallback(CompleteBatch completeBatch, FutureCallback callback) { - this.completeBatch = completeBatch; + public PostBatchDataCallback(BulletinBoardMessage msg, BatchIdentifier identifier, FutureCallback callback) { + this.msg = msg; + this.identifier = identifier; this.callback = callback; } @Override - public void onSuccess(Boolean msg) { + public void onSuccess(Boolean result) { closeBatch( - completeBatch.getCloseBatchMessage(), + identifier, + msg.getMsg().getTimestamp(), + msg.getSigList(), callback ); } @@ -391,25 +395,28 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } - private class BeginBatchCallback implements FutureCallback { + private class ContinueBatchCallback implements FutureCallback { - private final CompleteBatch completeBatch; + private final BulletinBoardMessage msg; + private final int chunkSize; private final FutureCallback callback; - public BeginBatchCallback(CompleteBatch completeBatch, FutureCallback callback) { - this.completeBatch = completeBatch; + public ContinueBatchCallback(BulletinBoardMessage msg, int chunkSize, FutureCallback callback) { + this.msg = msg; + this.chunkSize = chunkSize; this.callback = callback; } @Override - public void onSuccess(Boolean msg) { + public void onSuccess(BatchIdentifier identifier) { + + List batchChunkList = BulletinBoardUtils.breakToBatch(msg, chunkSize); postBatchData( - completeBatch.getBeginBatchMessage().getSignerId(), - completeBatch.getBeginBatchMessage().getBatchId(), - completeBatch.getBatchDataList(), + identifier, + batchChunkList, 0, - new PostBatchDataCallback(completeBatch,callback)); + new PostBatchDataCallback(msg, identifier, callback)); } @Override @@ -420,45 +427,80 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public MessageID postBatch(CompleteBatch completeBatch, FutureCallback callback) { + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize, FutureCallback callback) { beginBatch( - completeBatch.getBeginBatchMessage(), - new BeginBatchCallback(completeBatch, callback) + msg.getMsg().getTagList(), + new ContinueBatchCallback(msg, chunkSize, callback) ); - digest.update(completeBatch); + digest.update(msg); return digest.digestAsMessageID(); } + private class BeginBatchCallback implements FutureCallback { + + private final FutureCallback callback; + + public BeginBatchCallback(FutureCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(Int64Value result) { + callback.onSuccess(new SingleServerBatchIdentifier(result)); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + } + @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + public void beginBatch(Iterable tags, FutureCallback callback) { + + BeginBatchMessage beginBatchMessage = BeginBatchMessage.newBuilder() + .addAllTag(tags) + .build(); // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerBeginBatchWorker worker = new SingleServerBeginBatchWorker(meerkatDBs.get(0), beginBatchMessage, MAX_RETRIES); // Submit worker and create callback - scheduleWorker(worker, new RetryCallback<>(worker, callback)); + scheduleWorker(worker, new RetryCallback<>(worker, new BeginBatchCallback(callback))); } - @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback) { - BatchMessage.Builder builder = BatchMessage.newBuilder() - .setSignerId(signerId) - .setBatchId(batchId); + @Override + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, + int startPosition, FutureCallback callback) throws IllegalArgumentException{ + + // Cast identifier to usable form + + if (!(batchIdentifier instanceof SingleServerBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + SingleServerBatchIdentifier identifier = (SingleServerBatchIdentifier) batchIdentifier; + + // Update batch size + + identifier.setLength(startPosition + batchChunkList.size()); // Create a unified callback to aggregate successful posts - PostBatchDataListCallback listCallback = new PostBatchDataListCallback(batchChunkList.size(), callback); + PostBatchChunkListCallback listCallback = new PostBatchChunkListCallback(batchChunkList.size(), callback); // Iterate through data list + BatchMessage.Builder builder = BatchMessage.newBuilder() + .setBatchId(identifier.getBatchId().getValue()); + for (BatchChunk data : batchChunkList) { builder.setSerialNum(startPosition).setData(data); @@ -476,29 +518,29 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, FutureCallback callback) { + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, FutureCallback callback) + throws IllegalArgumentException { - postBatchData(signerId, batchId, batchChunkList, 0, callback); + postBatchData(batchIdentifier, batchChunkList, 0, callback); } @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback) { + public void closeBatch(BatchIdentifier batchIdentifier, Timestamp timestamp, Iterable signatures, FutureCallback callback) + throws IllegalArgumentException { - postBatchData(ByteString.copyFrom(signerId), batchId, batchChunkList, startPosition, callback); + if (!(batchIdentifier instanceof SingleServerBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } - } + SingleServerBatchIdentifier identifier = (SingleServerBatchIdentifier) batchIdentifier; - @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, FutureCallback callback) { - - postBatchData(signerId, batchId, batchChunkList, 0, callback); - - } - - @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() + .setBatchId(identifier.getBatchId().getValue()) + .setBatchLength(identifier.getLength()) + .setTimestamp(timestamp) + .addAllSig(signatures) + .build(); // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerCloseBatchWorker worker = @@ -532,29 +574,26 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + public void readBatch(MessageID msgID, FutureCallback callback) { - // Create job with no retries for retrieval of the Bulletin Board Message that defines the batch + // Create job with MAX retries for retrieval of the Bulletin Board Message that defines the batch MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_TAG) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.TAG) - .setTag(BulletinBoardConstants.BATCH_ID_TAG_PREFIX + batchSpecificationMessage.getBatchId()) - .build()) - .addFilter(MessageFilter.newBuilder() - .setType(FilterType.SIGNER_ID) - .setId(batchSpecificationMessage.getSignerId()) + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) .build()) .build(); - SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(msgID) + .setStartPosition(0) + .build(); - // Create job with no retries for retrieval of the Batch Data List - SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchSpecificationMessage, 1); + SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, MAX_RETRIES); + + // Create job with MAX retries for retrieval of the Batch Data List + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); // Create callback that will combine the two worker products CompleteBatchReadCallback completeBatchReadCallback = new CompleteBatchReadCallback(callback); @@ -565,6 +604,49 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } + private class ReadBatchCallback implements FutureCallback> { + + private final BulletinBoardMessage stub; + private final FutureCallback callback; + + public ReadBatchCallback(BulletinBoardMessage stub, FutureCallback callback) { + this.stub = stub; + this.callback = callback; + } + + @Override + public void onSuccess(List result) { + callback.onSuccess(BulletinBoardUtils.gatherBatch(stub, result)); + } + + @Override + public void onFailure(Throwable t) { + + } + } + + @Override + public void readBatchData(BulletinBoardMessage stub, FutureCallback callback) throws IllegalArgumentException{ + + if (stub.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { + throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); + } + + // Create job with MAX retries for retrieval of the Batch Data List + + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(MessageID.newBuilder() + .setID(stub.getMsg().getMsgId()) + .build()) + .setStartPosition(0) + .build(); + + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); + + scheduleWorker(batchWorker, new RetryCallback<>(batchWorker, new ReadBatchCallback(stub, callback))); + + } + @Override public void querySync(SyncQuery syncQuery, FutureCallback callback) { diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 289ffcf..7f8232f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -1,10 +1,12 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.multiserver.*; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Voting.*; import java.util.ArrayList; @@ -41,6 +43,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple private int minAbsoluteRedundancy; + /** * Stores database locations and initializes the web Client * Stores the required minimum redundancy. @@ -98,28 +101,28 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public MessageID postBatch(BulletinBoardMessage completeBatch, FutureCallback callback) { + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize, FutureCallback callback) { // Create job MultiServerPostBatchWorker worker = - new MultiServerPostBatchWorker(clients, minAbsoluteRedundancy, completeBatch, POST_MESSAGE_RETRY_NUM, callback); + new MultiServerPostBatchWorker(clients, minAbsoluteRedundancy, msg, chunkSize, POST_MESSAGE_RETRY_NUM, callback); // Submit job executorService.submit(worker); // Calculate the correct message ID and return it batchDigest.reset(); - batchDigest.update(completeBatch); + batchDigest.update(msg); return batchDigest.digestAsMessageID(); } @Override - public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback) { + public void beginBatch(Iterable tags, FutureCallback callback) { // Create job MultiServerBeginBatchWorker worker = - new MultiServerBeginBatchWorker(clients, minAbsoluteRedundancy, beginBatchMessage, POST_MESSAGE_RETRY_NUM, callback); + new MultiServerBeginBatchWorker(clients, minAbsoluteRedundancy, tags, POST_MESSAGE_RETRY_NUM, callback); // Submit job executorService.submit(worker); @@ -127,10 +130,18 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback) { + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, + int startPosition, FutureCallback callback) throws IllegalArgumentException { - BatchDataContainer batchDataContainer = new BatchDataContainer(signerId, batchId, batchChunkList, startPosition); + // Cast identifier to usable form + + if (!(batchIdentifier instanceof MultiServerBatchIdentifier)){ + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + MultiServerBatchIdentifier identifier = (MultiServerBatchIdentifier) batchIdentifier; + + BatchDataContainer batchDataContainer = new BatchDataContainer(identifier, batchChunkList, startPosition); // Create job MultiServerPostBatchDataWorker worker = @@ -142,33 +153,19 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, FutureCallback callback) { + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, FutureCallback callback) + throws IllegalArgumentException { - postBatchData(signerId, batchId, batchChunkList, 0, callback); + postBatchData(batchIdentifier, batchChunkList, 0, callback); } @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback) { - - postBatchData(signerId.toByteArray(), batchId, batchChunkList, startPosition, callback); - - } - - @Override - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, FutureCallback callback) { - - postBatchData(signerId, batchId, batchChunkList, 0, callback); - - } - - @Override - public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback) { + public void closeBatch(BatchIdentifier payload, Timestamp timestamp, Iterable signatures, FutureCallback callback) { // Create job MultiServerCloseBatchWorker worker = - new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, closeBatchMessage, POST_MESSAGE_RETRY_NUM, callback); + new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, payload, timestamp, signatures, POST_MESSAGE_RETRY_NUM, callback); // Submit job executorService.submit(worker); @@ -211,11 +208,29 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(BatchSpecificationMessage batchSpecificationMessage, FutureCallback callback) { + public void readBatch(MessageID msgID, FutureCallback callback) { + + //Create job + MultiServerReadBatchWorker worker = + new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, msgID, READ_MESSAGES_RETRY_NUM, callback); + + // Submit job + executorService.submit(worker); + + } + + @Override + public void readBatchData(BulletinBoardMessage stub, FutureCallback callback) throws IllegalArgumentException { + + if (stub.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { + throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); + } + + MessageID msgID = MessageID.newBuilder().setID(stub.getMsg().getMsgId()).build(); // Create job - MultiServerReadBatchWorker worker = - new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, batchSpecificationMessage, READ_MESSAGES_RETRY_NUM, callback); + MultiServerReadBatchDataWorker worker = + new MultiServerReadBatchDataWorker(clients, minAbsoluteRedundancy, msgID, READ_MESSAGES_RETRY_NUM, callback); // Submit job executorService.submit(worker); @@ -251,4 +266,3 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } } -==== BASE ==== diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java index e0e92bb..793fc6e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java @@ -1,28 +1,96 @@ package meerkat.bulletinboard.workers.multiserver; import com.google.common.util.concurrent.FutureCallback; +import meerkat.bulletinboard.MultiServerBatchIdentifier; +import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; -import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage; +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; +import meerkat.comm.CommunicationException; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerBeginBatchWorker extends MultiServerGenericPostWorker { +public class MultiServerBeginBatchWorker extends MultiServerWorker, BatchIdentifier> { + + private BatchIdentifier[] identifiers; + private AtomicInteger remainingServers; public MultiServerBeginBatchWorker(List clients, - int minServers, BeginBatchMessage payload, int maxRetry, - FutureCallback futureCallback) { + int minServers, Iterable payload, int maxRetry, + FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); + identifiers = new BatchIdentifier[clients.size()]; + + for (int i = 0 ; i < identifiers.length ; i++) { + identifiers[i] = null; + } + + remainingServers = new AtomicInteger(clients.size()); + + } + + private class BeginBatchCallback implements FutureCallback { + + private final int clientNum; + + public BeginBatchCallback(int clientNum) { + this.clientNum = clientNum; + } + + private void finishPost() { + + if (remainingServers.decrementAndGet() <= 0){ + + if (minServers.get() <= 0) { + MultiServerBeginBatchWorker.this.onSuccess(new MultiServerBatchIdentifier(identifiers)); + } else { + MultiServerBeginBatchWorker.this.onFailure(new CommunicationException("Could not open batch in enough servers")); + } + } + + } + + @Override + public void onSuccess(BatchIdentifier result) { + + identifiers[clientNum] = result; + finishPost(); + + } + + @Override + public void onFailure(Throwable t) { + finishPost(); + } } @Override - protected void doPost(SingleServerBulletinBoardClient client, BeginBatchMessage payload) { - client.beginBatch(payload, this); + public void onSuccess(BatchIdentifier result) { + succeed(result); } + @Override + public void onFailure(Throwable t) { + fail(t); + } + @Override + public void run() { + + int clientNum = 0; + + for (SingleServerBulletinBoardClient client : clients){ + + client.beginBatch(payload, new BeginBatchCallback(clientNum)); + + clientNum++; + + } + + } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java index 300440f..68aa8ef 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerCloseBatchWorker.java @@ -1,27 +1,35 @@ package meerkat.bulletinboard.workers.multiserver; import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.Timestamp; +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; import meerkat.bulletinboard.SingleServerBulletinBoardClient; -import meerkat.protobuf.BulletinBoardAPI.CloseBatchMessage; +import meerkat.protobuf.Crypto.Signature; import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerCloseBatchWorker extends MultiServerGenericPostWorker { +public class MultiServerCloseBatchWorker extends MultiServerGenericPostWorker { - public MultiServerCloseBatchWorker(List clients, - int minServers, CloseBatchMessage payload, int maxRetry, - FutureCallback futureCallback) { + private final Timestamp timestamp; + private final Iterable signatures; + + public MultiServerCloseBatchWorker(List clients, int minServers, + BatchIdentifier payload, Timestamp timestamp, Iterable signatures, + int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); + this.timestamp = timestamp; + this.signatures = signatures; + } @Override - protected void doPost(SingleServerBulletinBoardClient client, CloseBatchMessage payload) { - client.closeBatch(payload, this); + protected void doPost(SingleServerBulletinBoardClient client, BatchIdentifier payload) { + client.closeBatch(payload, timestamp, signatures, this); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java index 8172e14..a720eda 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericPostWorker.java @@ -35,14 +35,9 @@ public abstract class MultiServerGenericPostWorker extends MultiServerWorker< public void run() { // Iterate through servers - - Iterator clientIterator = getClientIterator(); - - while (clientIterator.hasNext()) { + for (SingleServerBulletinBoardClient client : clients) { // Send request to Server - SingleServerBulletinBoardClient client = clientIterator.next(); - doPost(client, payload); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java index 88b4ac1..f17708b 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGenericReadWorker.java @@ -14,7 +14,9 @@ import java.util.List; */ public abstract class MultiServerGenericReadWorker extends MultiServerWorker{ - private final Iterator clientIterator; + private Iterator clientIterator; + + private String errorString; public MultiServerGenericReadWorker(List clients, int minServers, IN payload, int maxRetry, @@ -22,7 +24,8 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW super(clients, true, minServers, payload, maxRetry, futureCallback); // Shuffle clients on creation to balance load - clientIterator = getClientIterator(); + clientIterator = clients.iterator(); + errorString = ""; } @@ -46,7 +49,7 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW doRead(payload, client); } else { - fail(new CommunicationException("Could not contact any server")); + fail(new CommunicationException("Could not contact any server. Errors follow:\n" + errorString)); } } @@ -58,6 +61,8 @@ public abstract class MultiServerGenericReadWorker extends MultiServerW @Override public void onFailure(Throwable t) { + //TODO: log + errorString += t.getCause() + " " + t.getMessage() + "\n"; run(); // Retry with next server } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java index 748916b..b76a94f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerGetRedundancyWorker.java @@ -36,13 +36,8 @@ public class MultiServerGetRedundancyWorker extends MultiServerWorker clientIterator = getClientIterator(); - // Iterate through clients - - while (clientIterator.hasNext()) { - - SingleServerBulletinBoardClient client = clientIterator.next(); + for (SingleServerBulletinBoardClient client : clients) { // Send request to client client.getRedundancy(payload,this); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java index ca7b4fd..052b625 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java @@ -1,15 +1,18 @@ package meerkat.bulletinboard.workers.multiserver; import com.google.common.util.concurrent.FutureCallback; +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; +import meerkat.bulletinboard.MultiServerWorker; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.bulletinboard.BatchDataContainer; +import java.util.Iterator; import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerPostBatchDataWorker extends MultiServerGenericPostWorker { +public class MultiServerPostBatchDataWorker extends MultiServerWorker { public MultiServerPostBatchDataWorker(List clients, int minServers, BatchDataContainer payload, int maxRetry, @@ -20,9 +23,50 @@ public class MultiServerPostBatchDataWorker extends MultiServerGenericPostWorker } @Override - protected void doPost(SingleServerBulletinBoardClient client, BatchDataContainer payload) { - client.postBatchData(payload.signerId, payload.batchId, payload.batchChunkList, payload.startPosition, this); + public void run() { + + Iterator identifierIterator = payload.batchId.getIdentifiers().iterator(); + + // Iterate through client + + for (SingleServerBulletinBoardClient client : clients) { + + if (identifierIterator.hasNext()) { + + // Fetch the batch identifier supplied by the specific client (may be null if batch open failed on client + + BatchIdentifier identifier = identifierIterator.next(); + + if (identifier != null) { + + // Post the data with the matching identifier to the client + client.postBatchData(identifierIterator.next(), payload.batchChunkList, payload.startPosition, this); + + } else { + + // Count servers with no batch identifier as failed + maxFailedServers.decrementAndGet(); + + } + + } + + } + } + @Override + public void onSuccess(Boolean result) { + if (minServers.decrementAndGet() <= 0){ + succeed(result); + } + } + + @Override + public void onFailure(Throwable t) { + if (maxFailedServers.decrementAndGet() <= 0){ + fail(t); + } + } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java index 5b5198c..b938f52 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchWorker.java @@ -11,17 +11,23 @@ import java.util.List; */ public class MultiServerPostBatchWorker extends MultiServerGenericPostWorker { + private final int chunkSize; + public MultiServerPostBatchWorker(List clients, - int minServers, BulletinBoardMessage payload, int maxRetry, + int minServers, BulletinBoardMessage payload, int chunkSize, int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); + this.chunkSize = chunkSize; + } @Override protected void doPost(SingleServerBulletinBoardClient client, BulletinBoardMessage payload) { - client.postBatch(payload, this); + + client.postAsBatch(payload, chunkSize, this); + } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java new file mode 100644 index 0000000..959c60f --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java @@ -0,0 +1,29 @@ +package meerkat.bulletinboard.workers.multiserver; + +import com.google.common.util.concurrent.FutureCallback; +import meerkat.bulletinboard.SingleServerBulletinBoardClient; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + */ +public class MultiServerReadBatchDataWorker extends MultiServerGenericReadWorker { + + public MultiServerReadBatchDataWorker(List clients, + int minServers, MessageID payload, int maxRetry, + FutureCallback futureCallback) { + + super(clients, minServers, payload, maxRetry, futureCallback); + + } + + @Override + protected void doRead(MessageID payload, SingleServerBulletinBoardClient client) { + client.readBatch(payload, this); + } + + +} diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java index db58247..59b4ce5 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java @@ -3,7 +3,7 @@ package meerkat.bulletinboard.workers.multiserver; import com.google.common.util.concurrent.FutureCallback; import meerkat.bulletinboard.SingleServerBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.BatchSpecificationMessage; +import meerkat.protobuf.BulletinBoardAPI.MessageID; import java.util.List; @@ -11,10 +11,10 @@ import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { +public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { public MultiServerReadBatchWorker(List clients, - int minServers, BatchSpecificationMessage payload, int maxRetry, + int minServers, MessageID payload, int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); @@ -22,7 +22,7 @@ public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { +public class SingleServerBeginBatchWorker extends SingleServerWorker { public SingleServerBeginBatchWorker(String serverAddress, BeginBatchMessage payload, int maxRetry) { - super(serverAddress, BEGIN_BATCH_PATH, payload, maxRetry); + super(serverAddress, payload, maxRetry); } + @Override + public Int64Value call() throws Exception { + Client client = clientLocal.get(); + + WebTarget webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(BEGIN_BATCH_PATH); + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post( + Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF)); + + try { + + return response.readEntity(Int64Value.class); + + } catch (ProcessingException | IllegalStateException e) { + + // Post to this server failed + throw new CommunicationException("Could not contact the server"); + + } + finally { + response.close(); + } + } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java index ee2e193..8bc4bcd 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerReadBatchWorker.java @@ -17,14 +17,12 @@ import java.util.List; import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH; import static meerkat.bulletinboard.BulletinBoardConstants.READ_BATCH_PATH; -import static meerkat.bulletinboard.BulletinBoardConstants.BATCH_ID_TAG_PREFIX; - /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class SingleServerReadBatchWorker extends SingleServerWorker> { +public class SingleServerReadBatchWorker extends SingleServerWorker> { - public SingleServerReadBatchWorker(String serverAddress, BatchSpecificationMessage payload, int maxRetry) { + public SingleServerReadBatchWorker(String serverAddress, BatchQuery payload, int maxRetry) { super(serverAddress, payload, maxRetry); } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 6661491..dcea3e7 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -118,58 +118,43 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ new int[] {} ), - GET_BATCH_MESSAGE_ENTRY( - new String[] {"SignerId", "BatchId"}, - new int[] {Types.BLOB, Types.INTEGER} - ), - CHECK_BATCH_LENGTH( - new String[] {"SignerId", "BatchId"}, + new String[] {"BatchId"}, new int[] {Types.BLOB, Types.INTEGER} ), CHECK_BATCH_OPEN( - new String[] {"SignerId", "BatchId"}, + new String[] {"BatchId"}, new int[] {Types.BLOB, Types.INTEGER} ), - GET_BATCH_MESSAGE_DATA( + GET_BATCH_MESSAGE_DATA_BY_MSG_ID( new String[] {"MsgId", "StartPosition"}, new int[] {Types.BLOB, Types.INTEGER} ), - GET_BATCH_MESSAGE_DATA_BY_IDS( - new String[] {"SignerId", "BatchId", "StartPosition"}, - new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER} + GET_BATCH_MESSAGE_DATA_BY_BATCH_ID( + new String[] {"BatchId", "StartPosition"}, + new int[] {Types.INTEGER, Types.INTEGER} ), INSERT_BATCH_DATA( - new String[] {"SignerId", "BatchId", "SerialNum", "Data"}, - new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER, Types.BLOB} + new String[] {"BatchId", "SerialNum", "Data"}, + new int[] {Types.INTEGER, Types.INTEGER, Types.BLOB} ), STORE_BATCH_TAGS( - new String[] {"SignerId", "BatchId", "Tags"}, - new int[] {Types.BLOB, Types.INTEGER, Types.BLOB} + new String[] {"Tags"}, + new int[] {Types.BLOB} ), GET_BATCH_TAGS( - new String[] {"SignerId", "BatchId"}, - new int[] {Types.BLOB, Types.INTEGER} - ), - - REMOVE_BATCH_TAGS( - new String[] {"SignerId", "BatchId"}, - new int[] {Types.BLOB, Types.INTEGER} - ), - - REMOVE_BATCH_IDS( - new String[] {"SignerId", "BatchId"}, + new String[] {"BatchId"}, new int[] {Types.BLOB, Types.INTEGER} ), ADD_ENTRY_NUM_TO_BATCH( - new String[] {"SignerId", "BatchId", "EntryNum"}, + new String[] {"BatchId", "EntryNum"}, new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER} ); @@ -783,23 +768,21 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ return false; } - return messages.get(0).getMsg().getIsStub(); + return (messages.get(0).getMsg().getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.MSGID); } /** * This method checks if a specified batch exists and is still open - * @param signerId is the signer ID - * @param batchId is the batch ID + * @param batchId is the temporary batch ID * @return TRUE if the batch is closed and FALSE if it is still open or doesn't exist at all */ - private boolean isBatchOpen(ByteString signerId, int batchId) throws CommunicationException { + private boolean isBatchOpen(long batchId) throws CommunicationException { String sql = sqlQueryProvider.getSQLString(QueryType.CHECK_BATCH_OPEN); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.CHECK_BATCH_OPEN.getParamName(0),signerId.toByteArray()); - namedParameters.addValue(QueryType.CHECK_BATCH_OPEN.getParamName(1),batchId); + namedParameters.addValue(QueryType.CHECK_BATCH_OPEN.getParamName(0),batchId); List result = jdbcTemplate.query(sql, namedParameters, new LongMapper()); @@ -808,24 +791,22 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ } @Override - public BoolValue beginBatch(BeginBatchMessage message) throws CommunicationException { - - // Check if batch is already open - if (isBatchOpen(message.getSignerId(), message.getBatchId())) { - return BoolValue.newBuilder().setValue(false).build(); - } + public Int64Value beginBatch(BeginBatchMessage message) throws CommunicationException { // Store tags String sql = sqlQueryProvider.getSQLString(QueryType.STORE_BATCH_TAGS); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(0),message.getSignerId().toByteArray()); - namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(1),message.getBatchId()); - namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(2),message.toByteArray()); + namedParameters.addValue(QueryType.STORE_BATCH_TAGS.getParamName(0),message.toByteArray()); jdbcTemplate.update(sql,namedParameters); - return BoolValue.newBuilder().setValue(true).build(); + KeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(sql, namedParameters, keyHolder); + + long entryNum = keyHolder.getKey().longValue(); + + return Int64Value.newBuilder().setValue(entryNum).build(); } @@ -834,7 +815,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ public BoolValue postBatchMessage(BatchMessage batchMessage) throws CommunicationException{ // Make sure batch is open - if (!isBatchOpen(batchMessage.getSignerId(), batchMessage.getBatchId())) { + if (!isBatchOpen(batchMessage.getBatchId())) { return BoolValue.newBuilder().setValue(false).build(); } @@ -842,10 +823,9 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ String sql = sqlQueryProvider.getSQLString(QueryType.INSERT_BATCH_DATA); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId().toByteArray()); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId()); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum()); - namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData().toByteArray()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getBatchId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getSerialNum()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getData().toByteArray()); jdbcTemplate.update(sql, namedParameters); @@ -857,8 +837,6 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public BoolValue closeBatch(CloseBatchMessage message) throws CommunicationException { - ByteString signerId = message.getSig(0).getSignerId(); - int batchId = message.getBatchId(); // Check batch size @@ -866,8 +844,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),signerId.toByteArray()); - namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),batchId); + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),message.getBatchId()); List lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); @@ -880,8 +857,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_TAGS); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId.toByteArray()); - namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(1),batchId); + namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),message.getBatchId()); List beginBatchMessages = jdbcTemplate.query(sql, namedParameters, new BeginBatchMessageMapper()); @@ -892,7 +868,6 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ UnsignedBulletinBoardMessage unsignedMessage = UnsignedBulletinBoardMessage.newBuilder() .addAllTag(beginBatchMessages.get(0).getTagList()) .setTimestamp(message.getTimestamp()) - .setIsStub(true) .build(); // Digest the data @@ -900,12 +875,11 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ digest.reset(); digest.update(unsignedMessage); - sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS); + sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID); namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(0),signerId.toByteArray()); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(1),batchId); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(2),0); // Read from the beginning + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(0),message.getBatchId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(1),0); // Read from the beginning jdbcTemplate.query(sql, namedParameters, new BatchDataDigestHandler(digest)); byte[] msgID = digest.digest(); @@ -914,33 +888,21 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ // Create Bulletin Board message BulletinBoardMessage bulletinBoardMessage = BulletinBoardMessage.newBuilder() - .setMsg(unsignedMessage) + .setMsg(UnsignedBulletinBoardMessage.newBuilder() + .mergeFrom(unsignedMessage) + .setMsgId(ByteString.copyFrom(msgID))) .addAllSig(message.getSigList()) .build(); // Post message with pre-calculated ID and without checking signature validity long entryNum = postMessage(bulletinBoardMessage, msgID); - // Remove signer ID and batch ID from batch data table - // This allows reuse of the batch ID in subsequent batches - - sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_IDS); - - namedParameters = new MapSqlParameterSource(); - - namedParameters.addValue(QueryType.REMOVE_BATCH_IDS.getParamName(0), signerId.toByteArray()); - namedParameters.addValue(QueryType.REMOVE_BATCH_IDS.getParamName(1), batchId); - - jdbcTemplate.update(sql, namedParameters); - - // Remove tags from temporary table - sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_TAGS); - - jdbcTemplate.update(sql, namedParameters); - // Add entry num to tag data table sql = sqlQueryProvider.getSQLString(QueryType.ADD_ENTRY_NUM_TO_BATCH); - namedParameters.addValue(QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(2), entryNum); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(0), message.getBatchId()); + namedParameters.addValue(QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1), entryNum); jdbcTemplate.update(sql, namedParameters); @@ -959,11 +921,11 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ throw new IllegalArgumentException("No such batch"); } - String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); + String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),batchQuery.getMsgID().getID().toByteArray()); - namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),batchQuery.getStartPosition()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(0),batchQuery.getMsgID().getID().toByteArray()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(1),batchQuery.getStartPosition()); jdbcTemplate.query(sql, namedParameters, new BatchDataCallbackHandler(out)); @@ -1031,7 +993,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ checksumChanged = true; - checksum.update(message.getMsg().getData()); + checksum.update(message.getMsg().getMsgId()); lastTimestamp = message.getMsg().getTimestamp(); message = messageIterator.next(); @@ -1109,7 +1071,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ // Advance checksum - ByteString messageID = message.getMsg().getData(); // The data field contains the message ID + ByteString messageID = message.getMsg().getMsgId(); // The data field contains the message ID checksum.update(messageID); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java index 2f31e9e..872e226 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -94,90 +94,55 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider 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: + case GET_BATCH_MESSAGE_DATA_BY_MSG_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" + " INNER JOIN MsgTable ON MsgTable.EntryNum = BatchTable.EntryNum" + " WHERE MsgTable.MsgId = :{0} AND BatchTable.SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(1)); - case GET_BATCH_MESSAGE_DATA_BY_IDS: + case GET_BATCH_MESSAGE_DATA_BY_BATCH_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" - + " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}" + + " WHERE BatchId = :{0} AND SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(1), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(2)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(1)); case INSERT_BATCH_DATA: return MessageFormat.format( - "INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)" - + " VALUES (:{0}, :{1}, :{2}, :{3})", + "INSERT INTO BatchTable (BatchId, SerialNum, Data) VALUES (:{0}, :{1}, :{2})", QueryType.INSERT_BATCH_DATA.getParamName(0), QueryType.INSERT_BATCH_DATA.getParamName(1), - QueryType.INSERT_BATCH_DATA.getParamName(2), - QueryType.INSERT_BATCH_DATA.getParamName(3)); + QueryType.INSERT_BATCH_DATA.getParamName(2)); 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)); + "SELECT COUNT(Data) AS BatchLength FROM BatchTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_LENGTH.getParamName(0)); case CHECK_BATCH_OPEN: return MessageFormat.format( - "SELECT COUNT(SignerId) AS signCount FROM BatchTagTable" - + " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.CHECK_BATCH_OPEN.getParamName(0), - QueryType.CHECK_BATCH_OPEN.getParamName(1)); + "SELECT COUNT(BatchId) AS batchCount FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_OPEN.getParamName(0)); case STORE_BATCH_TAGS: return MessageFormat.format( - "INSERT INTO BatchTagTable (SignerId, BatchId, Tags) VALUES (:{0}, :{1}, :{2})", - QueryType.STORE_BATCH_TAGS.getParamName(0), - QueryType.STORE_BATCH_TAGS.getParamName(1), - QueryType.STORE_BATCH_TAGS.getParamName(2)); + "INSERT INTO BatchTagTable (Tags) VALUES (:{0})", + QueryType.STORE_BATCH_TAGS.getParamName(0)); case GET_BATCH_TAGS: return MessageFormat.format( - "SELECT Tags FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}", - 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)); - - case REMOVE_BATCH_IDS: - return MessageFormat.format( - "UPDATE BatchTable Set (SignerId, BatchId) = (NULL, NULL)" + - " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.REMOVE_BATCH_IDS.getParamName(0), - QueryType.REMOVE_BATCH_IDS.getParamName(1)); + "SELECT Tags FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.GET_BATCH_TAGS.getParamName(0)); case ADD_ENTRY_NUM_TO_BATCH: return MessageFormat.format( - "UPDATE BatchTable SET EntryNum = :{2} WHERE SignerId = :{0} AND BatchId = :{1}", + "UPDATE BatchTable SET EntryNum = :{1} WHERE BatchId = :{0}", QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(0), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(2)); + QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1)); default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); @@ -266,7 +231,8 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider public List getSchemaCreationCommands() { List list = new LinkedList(); - 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 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)"); @@ -281,12 +247,14 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignatureIndex ON SignatureTable(SignerId, EntryNum)"); - list.add("CREATE TABLE IF NOT EXISTS BatchTable (EntryNum INT, SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB," - + " UNIQUE(SignerId, BatchId, SerialNum))"); + list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (BatchId INT AUTO_INCREMENT PRIMARY KEY, Tags BLOB)"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTable (BatchId INT, EntryNum INT, SerialNum INT, Data BLOB," + + " UNIQUE(BatchId, SerialNum)," + + " FOREIGN KEY (BatchId) REFERENCES BatchTagTable(BatchId) ON DELETE CASCADE)"); list.add("CREATE INDEX IF NOT EXISTS BatchDataIndex ON BatchTable(EntryNum, SerialNum)"); - list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, Tags BLOB)"); - list.add("CREATE UNIQUE INDEX IF NOT EXISTS BatchTagIndex 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 @@ -302,12 +270,12 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider list.add("DROP TABLE IF EXISTS UtilityTable"); - list.add("DROP INDEX IF EXISTS BatchTagIndex"); - list.add("DROP TABLE IF EXISTS BatchTagTable"); - list.add("DROP INDEX IF EXISTS BatchDataIndex"); list.add("DROP TABLE IF EXISTS BatchTable"); + list.add("DROP INDEX IF EXISTS BatchTagIndex"); + list.add("DROP TABLE IF EXISTS BatchTagTable"); + list.add("DROP TABLE IF EXISTS MsgTagTable"); list.add("DROP INDEX IF EXISTS SignerIdIndex"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index 2931a34..097095f 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -97,90 +97,55 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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: + case GET_BATCH_MESSAGE_DATA_BY_MSG_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" + " INNER JOIN MsgTable ON MsgTable.EntryNum = BatchTable.EntryNum" + " WHERE MsgTable.MsgId = :{0} AND BatchTable.SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(1)); - case GET_BATCH_MESSAGE_DATA_BY_IDS: + case GET_BATCH_MESSAGE_DATA_BY_BATCH_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" - + " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}" + + " WHERE BatchId = :{0} AND SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(1), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(2)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(1)); case INSERT_BATCH_DATA: return MessageFormat.format( - "INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)" - + " VALUES (:{0}, :{1}, :{2}, :{3})", + "INSERT INTO BatchTable (BatchId, SerialNum, Data) VALUES (:{0}, :{1}, :{2})", QueryType.INSERT_BATCH_DATA.getParamName(0), QueryType.INSERT_BATCH_DATA.getParamName(1), - QueryType.INSERT_BATCH_DATA.getParamName(2), - QueryType.INSERT_BATCH_DATA.getParamName(3)); + QueryType.INSERT_BATCH_DATA.getParamName(2)); 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)); + "SELECT COUNT(Data) AS BatchLength FROM BatchTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_LENGTH.getParamName(0)); case CHECK_BATCH_OPEN: return MessageFormat.format( - "SELECT COUNT(Tags) AS signCount FROM BatchTagTable" - + " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.CHECK_BATCH_OPEN.getParamName(0), - QueryType.CHECK_BATCH_OPEN.getParamName(1)); + "SELECT COUNT(BatchId) AS batchCount FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_OPEN.getParamName(0)); case STORE_BATCH_TAGS: return MessageFormat.format( - "INSERT INTO BatchTagTable (SignerId, BatchId, Tags) VALUES (:{0}, :{1}, :{2})", - QueryType.STORE_BATCH_TAGS.getParamName(0), - QueryType.STORE_BATCH_TAGS.getParamName(1), - QueryType.STORE_BATCH_TAGS.getParamName(2)); + "INSERT INTO BatchTagTable (Tags) VALUES (:{0})", + QueryType.STORE_BATCH_TAGS.getParamName(0)); case GET_BATCH_TAGS: return MessageFormat.format( - "SELECT Tags FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}", - 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)); - - case REMOVE_BATCH_IDS: - return MessageFormat.format( - "UPDATE BatchTable Set SignerId = NULL, BatchId = NULL" + - " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.REMOVE_BATCH_IDS.getParamName(0), - QueryType.REMOVE_BATCH_IDS.getParamName(1)); + "SELECT Tags FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.GET_BATCH_TAGS.getParamName(0)); case ADD_ENTRY_NUM_TO_BATCH: return MessageFormat.format( - "UPDATE BatchTable SET EntryNum = :{2} WHERE SignerId = :{0} AND BatchId = :{1}", + "UPDATE BatchTable SET EntryNum = :{1} WHERE BatchId = :{0}", QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(0), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(2)); + QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1)); default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); @@ -276,19 +241,21 @@ public class MySQLQueryProvider implements SQLQueryProvider { 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 FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE," + + " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId) ON DELETE CASCADE," + " 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))"); + + " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE)"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (BatchId INT AUTO_INCREMENT PRIMARY KEY, Tags BLOB)"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTable (BatchId INT, EntryNum INT, SerialNum INT, Data BLOB," + + " CONSTRAINT UNIQUE(BatchId, SerialNum)," + + " CONSTRAINT FOREIGN KEY (BatchId) REFERENCES BatchTagTable(BatchId) ON DELETE CASCADE)"); - list.add("CREATE TABLE IF NOT EXISTS BatchTable (EntryNum INT, 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, Tags BLOB," - + " INDEX(SignerId(32), BatchId))"); return list; } @@ -297,8 +264,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { public List getSchemaDeletionCommands() { List list = new LinkedList(); - list.add("DROP TABLE IF EXISTS BatchTagTable"); list.add("DROP TABLE IF EXISTS BatchTable"); + list.add("DROP TABLE IF EXISTS BatchTagTable"); list.add("DROP TABLE IF EXISTS MsgTagTable"); list.add("DROP TABLE IF EXISTS SignatureTable"); list.add("DROP TABLE IF EXISTS TagTable"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java index 0462543..9f68955 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard.sqlserver; import meerkat.protobuf.BulletinBoardAPI.*; +import org.apache.commons.dbcp2.BasicDataSource; import org.sqlite.SQLiteDataSource; import javax.sql.DataSource; @@ -60,91 +61,55 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi 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: + case GET_BATCH_MESSAGE_DATA_BY_MSG_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" + " INNER JOIN MsgTable ON MsgTable.EntryNum = BatchTable.EntryNum" + " WHERE MsgTable.MsgId = :{0} AND BatchTable.SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_MSG_ID.getParamName(1)); - case GET_BATCH_MESSAGE_DATA_BY_IDS: + case GET_BATCH_MESSAGE_DATA_BY_BATCH_ID: return MessageFormat.format( "SELECT Data FROM BatchTable" - + " WHERE SignerId = :{0} AND BatchId = :{1} AND SerialNum >= :{2}" + + " WHERE BatchId = :{0} AND SerialNum >= :{1}" + " ORDER BY BatchTable.SerialNum ASC", - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(0), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(1), - QueryType.GET_BATCH_MESSAGE_DATA_BY_IDS.getParamName(2)); + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA_BY_BATCH_ID.getParamName(1)); case INSERT_BATCH_DATA: return MessageFormat.format( - "INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)" - + " VALUES (:{0}, :{1}, :{2}, :{3})", + "INSERT INTO BatchTable (BatchId, SerialNum, Data) VALUES (:{0}, :{1}, :{2})", QueryType.INSERT_BATCH_DATA.getParamName(0), QueryType.INSERT_BATCH_DATA.getParamName(1), - QueryType.INSERT_BATCH_DATA.getParamName(2), - QueryType.INSERT_BATCH_DATA.getParamName(3)); + QueryType.INSERT_BATCH_DATA.getParamName(2)); 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)); + "SELECT COUNT(Data) AS BatchLength FROM BatchTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_LENGTH.getParamName(0)); case CHECK_BATCH_OPEN: return MessageFormat.format( - "SELECT COUNT(Tags) AS signCount FROM BatchTagTable" - + " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.CHECK_BATCH_OPEN.getParamName(0), - QueryType.CHECK_BATCH_OPEN.getParamName(1)); + "SELECT COUNT(BatchId) AS batchCount FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.CHECK_BATCH_OPEN.getParamName(0)); case STORE_BATCH_TAGS: return MessageFormat.format( - "INSERT INTO BatchTagTable (SignerId, BatchId, Tags) VALUES (:{0}, :{1}, :{2})", - QueryType.STORE_BATCH_TAGS.getParamName(0), - QueryType.STORE_BATCH_TAGS.getParamName(1), - QueryType.STORE_BATCH_TAGS.getParamName(2)); + "INSERT INTO BatchTagTable (Tags) VALUES (:{0})", + QueryType.STORE_BATCH_TAGS.getParamName(0)); 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)); - - case REMOVE_BATCH_IDS: - return MessageFormat.format( - "UPDATE BatchTable Set (SignerId, BatchId) = (NULL, NULL)" + - " WHERE SignerId = :{0} AND BatchId = :{1}", - QueryType.REMOVE_BATCH_IDS.getParamName(0), - QueryType.REMOVE_BATCH_IDS.getParamName(1)); + "SELECT Tags FROM BatchTagTable WHERE BatchId = :{0}", + QueryType.GET_BATCH_TAGS.getParamName(0)); case ADD_ENTRY_NUM_TO_BATCH: return MessageFormat.format( - "UPDATE BatchTable SET EntryNum = :{2} WHERE SignerId = :{0} AND BatchId = :{1}", + "UPDATE BatchTable SET EntryNum = :{1} WHERE BatchId = :{0}", QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(0), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1), - QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(2)); + QueryType.ADD_ENTRY_NUM_TO_BATCH.getParamName(1)); default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); @@ -220,7 +185,8 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi @Override public DataSource getDataSource() { - SQLiteDataSource dataSource = new SQLiteDataSource(); + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName("org.sqlite.JDBC"); dataSource.setUrl("jdbc:sqlite:" + dbName); return dataSource; @@ -234,14 +200,23 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi 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 MsgTagTable (EntryNum BLOB, TagId INTEGER," + + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE," + + " FOREIGN KEY (TagId) REFERENCES TagTable(TagId) ON DELETE CASCADE," + + " 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))"); + + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum) ON DELETE CASCADE," + + " UNIQUE(SignerId, EntryNum))"); list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); + list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (BatchId INTEGER PRIMARY KEY, Tags BLOB)"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTable (BatchId INTEGER, EntryNum INTEGER, SerialNum INTEGER, Data BLOB," + + " UNIQUE(BatchId, SerialNum)," + + " FOREIGN KEY (BatchId) REFERENCES BatchTagTable(BatchId) ON DELETE CASCADE)"); + return list; } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java index 1f9c459..e9174e5 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/MessageStubMapper.java @@ -21,7 +21,7 @@ public class MessageStubMapper implements RowMapper { return BulletinBoardMessage.newBuilder() .setEntryNum(rs.getLong(1)) .setMsg(UnsignedBulletinBoardMessage.newBuilder() - .setData(ByteString.copyFrom(rs.getBytes(2))) + .setMsgId(ByteString.copyFrom(rs.getBytes(2))) .setTimestamp(BulletinBoardUtils.toTimestampProto(rs.getTimestamp(3))) .build()) .build(); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 7389090..f9d3a94 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -10,6 +10,7 @@ import javax.ws.rs.core.StreamingOutput; import com.google.protobuf.BoolValue; import com.google.protobuf.Int32Value; +import com.google.protobuf.Int64Value; import meerkat.bulletinboard.BulletinBoardServer; import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; import meerkat.bulletinboard.sqlserver.H2QueryProvider; @@ -142,7 +143,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolValue beginBatch(BeginBatchMessage message) { + public Int64Value beginBatch(BeginBatchMessage message) { try { init(); return bulletinBoard.beginBatch(message); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index a5997a3..eafd80c 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -20,6 +20,7 @@ import java.util.*; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; +import com.google.protobuf.Int64Value; import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; import meerkat.comm.MessageInputStream; @@ -443,24 +444,18 @@ public class GenericBulletinBoardServerTest { } - private void postAsBatch(BulletinBoardMessage message, ByteString signerId, int batchId, int chunkSize, boolean close) throws CommunicationException { + private void postAsBatch(BulletinBoardMessage message, int chunkSize, boolean close) throws CommunicationException { List batchChunks = BulletinBoardUtils.breakToBatch(message, chunkSize); - BeginBatchMessage beginBatchMessage = BulletinBoardUtils.generateBeginBatchMessage(signerId, batchId, message); + BeginBatchMessage beginBatchMessage = BulletinBoardUtils.generateBeginBatchMessage(message); BoolValue result; // Begin batch - result = bulletinBoardServer.beginBatch(beginBatchMessage); + Int64Value batchId = bulletinBoardServer.beginBatch(beginBatchMessage); - assertThat("Was not able to open batch", result.getValue(), is(true)); - - // Attempt to open batch again - - result = bulletinBoardServer.beginBatch(beginBatchMessage); - - assertThat("Was able to open a closed batch", result.getValue(), is(false)); + assertThat("Was not able to open batch", batchId.getValue() != -1); // Post data @@ -469,8 +464,7 @@ public class GenericBulletinBoardServerTest { for (int i = 0 ; i < batchChunks.size() ; i++){ batchMessage = BatchMessage.newBuilder() - .setSignerId(signerId) - .setBatchId(batchId) + .setBatchId(batchId.getValue()) .setSerialNum(i) .setData(batchChunks.get(i)) .build(); @@ -494,45 +488,6 @@ public class GenericBulletinBoardServerTest { } - /** - * Tests that opening the same batch ID while one is open results in failure - * @throws CommunicationException - */ - public void testReopen() throws CommunicationException, SignatureException { - - // Create data - final int BATCH_ID = 100; - final int DATA_SIZE = 1; - final int CHUNK_SIZE = 1; - final int TAG_NUMBER = 1; - - Timestamp timestamp = Timestamp.newBuilder() - .setSeconds(141510) - .setNanos(48015) - .build(); - - BulletinBoardMessage batch = bulletinBoardMessageGenerator.generateRandomMessage(signers, timestamp, DATA_SIZE, TAG_NUMBER); - - // Post batch but do not close - - postAsBatch(batch, signerIDs[0], BATCH_ID, CHUNK_SIZE, false); - - // Attempt to open batch again - - BoolValue result; - - result = bulletinBoardServer.beginBatch(BulletinBoardUtils.generateBeginBatchMessage(signerIDs[0], BATCH_ID, batch)); - - assertThat("Was able to open a closed batch", result.getValue(), is(false)); - - // Close batch - - result = bulletinBoardServer.closeBatch(BulletinBoardUtils.generateCloseBatchMessage(BATCH_ID, DATA_SIZE / CHUNK_SIZE, batch)); - - assertThat("Was not able to close batch", result.getValue(), is(true)); - - } - /** * Posts a complete batch message * @throws CommunicationException @@ -554,7 +509,7 @@ public class GenericBulletinBoardServerTest { // Post batch - postAsBatch(batch, signerIDs[0], BATCH_ID, CHUNK_SIZE, true); + postAsBatch(batch, CHUNK_SIZE, true); // Update locally stored batches batches.add(batch); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java index 4ee2282..fa96635 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -106,16 +106,6 @@ public class H2BulletinBoardServerTest { System.err.println("Time of operation: " + (end - start)); } - @Test - public void testBatchReopen() { - try{ - serverTest.testReopen(); - } catch (Exception e) { - System.err.println(e.getMessage()); - fail(e.getMessage()); - } - } - @Test public void testBatch() { diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java index c4bd7fa..334620c 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -110,16 +110,6 @@ public class MySQLBulletinBoardServerTest { System.err.println("Time of operation: " + (end - start)); } - @Test - public void testBatchReopen() { - try{ - serverTest.testReopen(); - } catch (Exception e) { - System.err.println(e.getMessage()); - fail(e.getMessage()); - } - } - @Test public void testBatch() { diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java index 1d7aae0..4dcd97b 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java @@ -60,7 +60,7 @@ public class SQLiteBulletinBoardServerTest{ System.err.println("Time of operation: " + (end - start)); } - @Test +// @Test public void bulkTest() { System.err.println("Starting bulkTest of SQLiteBulletinBoardServerTest"); long start = threadBean.getCurrentThreadCpuTime(); @@ -91,6 +91,29 @@ public class SQLiteBulletinBoardServerTest{ System.err.println("Time of operation: " + (end - start)); } +// @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 SQLiteBulletinBoardServerTest"); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index fcc6394..42af8ef 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -1,8 +1,9 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Crypto.Signature; import java.util.List; @@ -21,68 +22,58 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback); /** - * Perform an end-to-end post of a signed batch message - * @param signerId is the canonical form for the ID of the sender of this batch - * @param batchId is a unique (per signer) ID for this batch - * @param completeBatch contains all the data of the batch including the meta-data and the signature + * Perform an end-to-end post of a message in batch form + * @param completeBatch contains all the data of the batch + * @param chunkSize is the maximum size of each chunk of the message in bytes * @param callback is a class containing methods to handle the result of the operation * @return a unique identifier for the batch message */ - public MessageID postBatch(byte[] signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback); + public MessageID postAsBatch(BulletinBoardMessage completeBatch, int chunkSize, FutureCallback callback); /** - * Perform an end-to-end post of a signed batch message - * @param signerId is the canonical form for the ID of the sender of this batch - * @param batchId is a unique (per signer) ID for this batch - * @param completeBatch contains all the data of the batch including the meta-data and the signature - * @param callback is a class containing methods to handle the result of the operation - * @return a unique identifier for the batch message + * An interface for returning an opaque identifier for a batch message + * This identifier is used to uniquely identify the batch until it is completely posted and signed + * After the batch is fully posted: it is identified by its digest (like any message) + * This can be implementation-specific (and not necessarily interchangeable between different implementations) */ - public MessageID postBatch(ByteString signerId, int batchId, BulletinBoardMessage completeBatch, FutureCallback callback); + public interface BatchIdentifier {} /** * This message informs the server about the existence of a new batch message and supplies it with the tags associated with it - * @param beginBatchMessage contains the data required to begin the batch + * @param tags contains the tags used in the batch * @param callback is a callback function class for handling results of the operation + * it receives a BatchIdentifier for use in subsequent batch post operations */ - public void beginBatch(BeginBatchMessage beginBatchMessage, FutureCallback callback); + public void beginBatch(Iterable tags, FutureCallback callback); /** * This method posts batch data into an (assumed to be open) batch * It does not close the batch - * @param signerId is the canonical form for the ID of the sender of this batch - * @param batchId is a unique (per signer) ID for this batch + * @param batchIdentifier is the temporary batch identifier * @param batchChunkList is the (canonically ordered) list of data comprising the portion of the batch to be posted * @param startPosition is the location (in the batch) of the first entry in batchDataList - * (optionally used to continue interrupted post operations) - * The first position in the batch is position 0 + * (optionally used to continue interrupted post operations) + * The first position in the batch is position 0 * @param callback is a callback function class for handling results of the operation + * @throws IllegalArgumentException if the batch identifier given was of an illegal format */ - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback); + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, + int startPosition, FutureCallback callback) throws IllegalArgumentException; /** * Overloading of the postBatchData method which starts at the first position in the batch */ - public void postBatchData(byte[] signerId, int batchId, List batchChunkList, FutureCallback callback); - - /** - * Overloading of the postBatchData method which uses ByteString - */ - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, - int startPosition, FutureCallback callback); - - /** - * Overloading of the postBatchData method which uses ByteString and starts at the first position in the batch - */ - public void postBatchData(ByteString signerId, int batchId, List batchChunkList, FutureCallback callback); + public void postBatchData(BatchIdentifier batchIdentifier, List batchChunkList, FutureCallback callback) + throws IllegalArgumentException; /** * Attempts to close a batch message - * @param closeBatchMessage contains the data required to close the batch + * @param batchIdentifier is the temporary batch identifier * @param callback is a callback function class for handling results of the operation + * @throws IllegalArgumentException if the batch identifier given was of an illegal format */ - public void closeBatch(CloseBatchMessage closeBatchMessage, FutureCallback callback); + public void closeBatch(BatchIdentifier batchIdentifier, Timestamp timestamp, Iterable signatures, FutureCallback callback) + throws IllegalArgumentException; /** * Check how "safe" a given message is in an asynchronous manner @@ -110,6 +101,15 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { */ public void readBatch(MessageID msgID, FutureCallback callback); + /** + * Read batch data for a specific stub message + * @param stub is a batch message stub + * @param callback is a callback class for handling the result of the operation + * @return a new BulletinBoardMessage containing both metadata from the stub and actual data from the server + * @throws IllegalArgumentException if the received message is not a stub + */ + public void readBatchData(BulletinBoardMessage stub, FutureCallback callback) throws IllegalArgumentException; + /** * Perform a Sync Query on the bulletin board diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 9ce3943..142bb35 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -45,14 +45,32 @@ public interface BulletinBoardClient { */ List readMessages(MessageFilterList filterList) throws CommunicationException; + /** + * Breaks up a bulletin board message into chunks and posts it as a batch message + * @param msg is the message to post + * @param chunkSize is the maximal chunk size in bytes + * @return the unique message ID + * @throws CommunicationException if operation is unsuccessful + */ + MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException; + /** * Read a given batch message from the bulletin board * @param msgID is the batch message ID to be read * @return the complete batch - * @throws CommunicationException + * @throws CommunicationException if operation is unsuccessful */ BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException; + /** + * Read batch data for a specific stub message + * @param stub is a batch message stub + * @return a new BulletinBoardMessage containing both metadata from the stub and actual data from the server + * @throws CommunicationException if operation is unsuccessful + * @throws IllegalArgumentException if the received message is not a stub + */ + BulletinBoardMessage readBatchData(BulletinBoardMessage stub) throws CommunicationException, IllegalArgumentException; + /** * 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) diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index 3d33704..8121b85 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -2,6 +2,7 @@ package meerkat.bulletinboard; import com.google.protobuf.BoolValue; import com.google.protobuf.Int32Value; +import com.google.protobuf.Int64Value; import meerkat.comm.CommunicationException; import meerkat.comm.MessageOutputStream; import meerkat.protobuf.BulletinBoardAPI.*; @@ -50,12 +51,10 @@ public interface BulletinBoardServer{ /** * 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 + * @return a unique batch identifier for the new batch ; -1 if batch creation was unsuccessful * @throws CommunicationException on DB connection error */ - public BoolValue beginBatch(BeginBatchMessage message) throws CommunicationException; + public Int64Value beginBatch(BeginBatchMessage message) throws CommunicationException; /** * Posts a chunk of a batch message to the bulletin board @@ -93,7 +92,7 @@ public interface BulletinBoardServer{ * @return The generated SyncQuery * @throws CommunicationException on DB connection error */ - SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException; + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException; /** * Queries the database for sync status with respect to a given sync query diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java index 9930ab3..fb7bd3f 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardDigest.java @@ -65,7 +65,7 @@ public class GenericBulletinBoardDigest implements BulletinBoardDigest { update(msg.getTimestamp()); - if (!msg.getIsStub()){ + if (msg.getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.DATA){ update(msg.getData().toByteArray()); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardSignature.java b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardSignature.java index e818071..aad6466 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardSignature.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/GenericBulletinBoardSignature.java @@ -42,7 +42,7 @@ public class GenericBulletinBoardSignature implements BulletinBoardSignature { updateContent(msg.getTimestamp()); - if (!msg.getIsStub()){ + if (msg.getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.DATA){ updateContent(msg.getData().toByteArray()); } diff --git a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java index ec9b2e0..7005568 100644 --- a/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java +++ b/meerkat-common/src/main/java/meerkat/util/BulletinBoardMessageComparator.java @@ -47,16 +47,20 @@ public class BulletinBoardMessageComparator implements Comparator Date: Mon, 20 Jun 2016 15:26:53 +0300 Subject: [PATCH 067/106] Fixed some stuff according to Arbel's suggestions. Specifically: 1. now handling exceptions in the encryption process (according to voter's choice) 2. handling files in storage manager (now reading election parameters and system messages from files) 3. Controller's init() now already sets all the info and parameters. No need to call extra functions 4. some more changes to the method structure --- .../src/main/proto/meerkat/voting.proto | 17 +- .../voting/controller/SystemMessages.java | 7 - .../controller/VotingBoothController.java | 21 +-- .../voting/controller/VotingBoothImpl.java | 166 +++++++++++------- .../callbacks/CastOrAuditCallback.java | 12 +- .../callbacks/ChannelChoiceCallback.java | 8 +- .../callbacks/EncryptionFailedCallback.java | 43 +++++ .../callbacks/OutputDeviceCommitCallback.java | 9 +- .../OutputDeviceFinalizeCallback.java | 9 +- .../controller/callbacks/VotingCallback.java | 8 +- .../callbacks/WaitForFinishCallback.java | 10 +- .../EncryptAndCommitBallotCommand.java | 8 +- .../RetryEncryptAndCommitBallotCommand.java | 10 ++ .../voting/encryptor/VBCryptoManager.java | 1 + .../voting/encryptor/VBCryptoManagerImpl.java | 2 + .../voting/storage/StorageManager.java | 17 ++ .../voting/storage/StorageManagerMockup.java | 25 ++- 17 files changed, 256 insertions(+), 117 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java create mode 100644 voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 4edc9f5..09c8b21 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -88,6 +88,10 @@ message BoothParams { } +message BoothSystemMessages { + map system_message = 1; +} + // A table to translate to and from compactly encoded answers // and their human-understandable counterparts. // This should be parsable by the UI @@ -122,14 +126,17 @@ message ElectionParams { // 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; + // questions to first indicate the voter's channel + repeated BallotQuestion channel_choice_questions = 6; - // Translation table between answers and plaintext encoding - //BallotAnswerTranslationTable answerTranslationTable = 7; + // translating the channel-choice answers to the voter's channel + SimpleCategoriesSelectionData selection_data = 7; + + // Candidate list (or other question format) + repeated BallotQuestion race_questions = 8; // Data required in order to access the Bulletin Board Servers - BulletinBoardClientParams bulletinBoardClientParams = 8; + BulletinBoardClientParams bulletinBoardClientParams = 9; } message Category { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java index ee6b506..4f57809 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java @@ -33,13 +33,6 @@ final public class SystemMessages { .build(); } - public static UIElement getFatalForceRestartMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Fatal error: Internal controller queue received unrecognized command. Force restarting the voting process.")) - .build(); - } - public static UIElement getRestartVotingButton() { return UIElement.newBuilder() .setType(UIElementDataType.TEXT) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index 6b706f3..e8eae93 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -7,6 +7,7 @@ import meerkat.voting.ui.VotingBoothUI; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; +import java.io.IOException; import java.util.List; @@ -25,25 +26,7 @@ public interface VotingBoothController extends Runnable{ public void init (BallotOutputDevice outputDevice, VBCryptoManager vbCrypto, VotingBoothUI vbUI, - StorageManager vbStorageManager); - - /** - * set the voting questions - * @param questions - */ - public void setBallotChannelChoiceQuestions(List questions); - - /** - * Set the channel question-selector (the component which matches the ballot questions to each user) - * @param selector the question selector instance - */ - public void setChannelQuestionSelector (QuestionSelector selector); - - /** - * set the voting race questions - * @param questions - */ - public void setBallotRaceQuestions(List questions); + StorageManager vbStorageManager) throws IOException; /** * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index a9221bf..b20a11d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,9 +1,11 @@ package meerkat.voting.controller; +import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.selector.QuestionSelector; +import meerkat.voting.controller.selector.SimpleListCategoriesSelector; import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.encryptor.VBCryptoManager.EncryptionAndSecrets; import meerkat.voting.output.BallotOutputDevice; @@ -15,6 +17,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.security.SignatureException; import java.util.List; +import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; /** @@ -29,6 +32,7 @@ public class VotingBoothImpl implements VotingBoothController { private List questionsForChoosingChannel; private List questions; private QuestionSelector questionSelector; + private Map systemMessages; private LinkedBlockingQueue queue; @@ -41,6 +45,7 @@ public class VotingBoothImpl implements VotingBoothController { private static int requestCounter = 0; + public VotingBoothImpl () { logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); @@ -53,30 +58,32 @@ public class VotingBoothImpl implements VotingBoothController { public void init(BallotOutputDevice outputDevice, VBCryptoManager vbCrypto, VotingBoothUI vbUI, - StorageManager vbStorageManager) { + StorageManager vbStorageManager) throws IOException { logger.info("init is called"); this.outputDevice = outputDevice; this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; + + ElectionParams electionParams; + try { + logger.info("init: reading election params"); + electionParams = storageManager.readElectionParams(); + logger.info("init: reading system messages"); + systemMessages = storageManager.readSystemMessages(); + } + catch (IOException e) { + logger.error("init could not read info from a file. Exception is: " + e); + throw e; + } + + logger.info("init: setting the election parameters"); + this.questionsForChoosingChannel = electionParams.getChannelChoiceQuestionsList(); + this.questions = electionParams.getRaceQuestionsList(); + this.questionSelector = new SimpleListCategoriesSelector(this.questions, electionParams.getSelectionData()); + logger.info("init: setting finished"); } - @Override - public void setBallotChannelChoiceQuestions(List questions) { - logger.info("setting questions"); - this.questionsForChoosingChannel = questions; - } - - @Override - public void setChannelQuestionSelector(QuestionSelector selector) { - this.questionSelector = selector; - } - - @Override - public void setBallotRaceQuestions(List questions) { - logger.info("setting questions"); - this.questions = questions; - } @Override public void run() { @@ -146,7 +153,7 @@ public class VotingBoothImpl implements VotingBoothController { } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); - doReportErrorAndForceRestart(SystemMessages.getSomethingWrongMessage()); + doReportErrorAndForceRestart(systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -156,18 +163,13 @@ public class VotingBoothImpl implements VotingBoothController { private void doShutDown () { logger.info("running callShutDown"); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.SHUT_DOWN; + state.clearAndResetState(VBState.SHUT_DOWN); //TODO: add commands to actually shut down the machine } private void doRestartVoting () { queue.clear(); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.NEW_VOTER; - state.currentBallotSerialNumber += 1; + state.clearAndResetState(VBState.NEW_VOTER); ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } @@ -178,13 +180,12 @@ public class VotingBoothImpl implements VotingBoothController { private void doReportErrorAndForceRestart(UIElement errorMessage) { queue.clear(); - state.clearPlaintext(); - state.clearCiphertext(); - state.stateIdentifier = VBState.FATAL_ERROR_FORCE_NEW_VOTER; - state.currentBallotSerialNumber += 1; + state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); ui.showErrorMessageWithButtons(errorMessage, - new UIElement[]{SystemMessages.getRestartVotingButton()}, - new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new UIElement[]{systemMessages.get(storageManager.RESTART_VOTING_BUTTON)}, + new ErrorMessageRestartCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue)); } private void doChooseChannel () { @@ -192,7 +193,10 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("doing chooseChannel"); state.stateIdentifier = VBState.CHOOSE_CHANNEL; ui.chooseChannel(this.questionsForChoosingChannel, - new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new ChannelChoiceCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); } else { logger.debug("doChooseChannel: current state is " + state.stateIdentifier); @@ -208,7 +212,10 @@ public class VotingBoothImpl implements VotingBoothController { state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, - new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new VotingCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.UNSUCCESSFUL_VOTING_MESSAGE))); } else { logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); @@ -223,7 +230,8 @@ public class VotingBoothImpl implements VotingBoothController { state.stateIdentifier = VBState.CAST_OR_AUDIT; ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, - this.queue)); + this.queue, + systemMessages.get(storageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); } else { logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); @@ -233,15 +241,33 @@ public class VotingBoothImpl implements VotingBoothController { private void doCommit (EncryptAndCommitBallotCommand task) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); - state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; - setBallotData (task); - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCommitMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), - state.currentBallotSerialNumber, - this.queue)); - outputDevice.commitToBallot(state.plaintextBallot, - state.signedEncryptedBallot, - new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + try { + setBallotData(task); + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_COMMIT_MESSAGE), + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + outputDevice.commitToBallot(state.plaintextBallot, + state.signedEncryptedBallot, + new OutputDeviceCommitCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; + } + catch (SignatureException | IOException e) { + logger.error("doCommit: encryption failed. exception: " + e); + UIElement errorMessage = systemMessages.get(storageManager.ENCRYPTION_FAILED_MESSAGE); + UIElement[] buttons = new UIElement[]{ + systemMessages.get(storageManager.RETRY_BUTTON), + systemMessages.get(storageManager.CANCEL_VOTE_BUTTON)}; + + EncryptionFailedCallback callback = new EncryptionFailedCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue); + ui.showErrorMessageWithButtons(errorMessage, buttons, callback); + } } else { logger.debug("doCommit: current state is " + state.stateIdentifier); @@ -249,18 +275,16 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void setBallotData (EncryptAndCommitBallotCommand task) { - state.plaintextBallot = PlaintextBallot.newBuilder() - .setSerialNumber(task.getBallotSerialNumber()) - .addAllAnswers(task.getVotingAnswers()) - .build(); - EncryptionAndSecrets encryptionAndSecrets = null; - try { - encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); - } - catch (SignatureException | IOException e) { - // TODO: handle exception + private void setBallotData (EncryptAndCommitBallotCommand task) throws IOException, SignatureException{ + if (! (task instanceof RetryEncryptAndCommitBallotCommand)) { + // this is not a retry attempt, so the plaintext is not set yet + // otherwise, we have the plaintext from the previous encryption attempt + state.plaintextBallot = PlaintextBallot.newBuilder() + .setSerialNumber(task.getBallotSerialNumber()) + .addAllAnswers(task.getVotingAnswers()) + .build(); } + EncryptionAndSecrets encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } @@ -270,16 +294,28 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForAuditMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_AUDIT_MESSAGE), + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.audit(state.secrets, - new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), - new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new WaitForFinishCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.castBallot( - new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); + new OutputDeviceFinalizeCallback(generateRequestIdentifier(), + state.currentBallotSerialNumber, + this.queue, + systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } } else { @@ -325,14 +361,22 @@ public class VotingBoothImpl implements VotingBoothController { } - public void clearPlaintext () { + private void clearPlaintext () { plaintextBallot = null; } - public void clearCiphertext () { + private void clearCiphertext () { signedEncryptedBallot = null; secrets = null; } + + public void clearAndResetState(VBState newStateIdentifier) { + state.clearPlaintext(); + state.clearCiphertext(); + state.stateIdentifier = newStateIdentifier; + state.currentBallotSerialNumber += 1; + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 69d5123..47ecd3b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -1,9 +1,8 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.*; import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; import meerkat.voting.ui.VotingBoothUI.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); + protected final UIElement unrecognizedFinalizeResponseMessage; public CastOrAuditCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unrecognizedFinalizeResponseMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unrecognizedFinalizeResponseMessage = unrecognizedFinalizeResponseMessage; } @Override @@ -31,7 +33,7 @@ public class CastOrAuditCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); + protected final UIElement unsuccessfulChannelChoiceMessage; public ChannelChoiceCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unsuccessfulChannelChoiceMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unsuccessfulChannelChoiceMessage = unsuccessfulChannelChoiceMessage; } @Override @@ -37,7 +39,7 @@ public class ChannelChoiceCallback extends ControllerCallback logger.error("channel choice initiated a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getUnsuccessfulChannelChoiceMessage())); + unsuccessfulChannelChoiceMessage)); } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java new file mode 100644 index 0000000..de7a61e --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java @@ -0,0 +1,43 @@ +package meerkat.voting.controller.callbacks; + +import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +import meerkat.voting.controller.commands.ControllerCommand; +import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.RetryEncryptAndCommitBallotCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; + +public class EncryptionFailedCallback extends ControllerCallback { + protected final static Logger logger = LoggerFactory.getLogger(EncryptionFailedCallback.class); + + public EncryptionFailedCallback(int requestId, + long ballotSerialNumber, + LinkedBlockingQueue controllerQueue) { + super(requestId, ballotSerialNumber, controllerQueue); + } + + @Override + public void onSuccess(Integer result) { + logger.debug("callback for voting returned success"); + int res = result.intValue(); + if (res == 0) { + logger.debug("voter chose to retry encryption"); + enqueueCommand(new RetryEncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else if (res == 1) { + logger.debug("voter chose to cancel the vote"); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } + else { + onFailure(new ValueException("EncryptionFailedCallback got an unknown result (" + res + ")")); + } + } + + @Override + public void onFailure(Throwable t) { + logger.error("Error message execution initiated a failure: " + t); + enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java index a6eaadf..a832572 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; import meerkat.voting.controller.commands.ReportErrorCommand; @@ -11,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class OutputDeviceCommitCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); + protected final UIElement outputDeviceFailureMessage; public OutputDeviceCommitCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement outputDeviceFailureMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.outputDeviceFailureMessage = outputDeviceFailureMessage; } @Override @@ -29,6 +32,6 @@ public class OutputDeviceCommitCallback extends ControllerCallback { logger.error("OutputDeviceCommitCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getOutputDeviceFailureMessage())); + outputDeviceFailureMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 74a85e0..414bdb0 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -1,6 +1,6 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ReportErrorCommand; import meerkat.voting.controller.commands.RestartVotingCommand; @@ -11,11 +11,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class OutputDeviceFinalizeCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); + protected final UIElement outputDeviceFailureMessage; public OutputDeviceFinalizeCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement outputDeviceFailureMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.outputDeviceFailureMessage = outputDeviceFailureMessage; } @Override @@ -29,6 +32,6 @@ public class OutputDeviceFinalizeCallback extends ControllerCallback { logger.error("OutputDeviceFinalizeCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getOutputDeviceFailureMessage())); + outputDeviceFailureMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 4b6f2f7..173fa82 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,7 +1,6 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.SystemMessages; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; import meerkat.voting.controller.commands.ReportErrorCommand; @@ -14,11 +13,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); + protected final UIElement unsuccessfulVotingMessage; public VotingCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement unsuccessfulVotingMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.unsuccessfulVotingMessage = unsuccessfulVotingMessage; } @Override @@ -37,7 +39,7 @@ public class VotingCallback extends ControllerCallback> { logger.error("voting initiated a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getUnsuccessfulVotingMessage())); + unsuccessfulVotingMessage)); } } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index 9f7a159..2634e27 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,9 +1,8 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.SystemMessages; +import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,11 +10,14 @@ import java.util.concurrent.LinkedBlockingQueue; public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); + protected final UIElement somethingWrongMessage; public WaitForFinishCallback(int requestId, long ballotSerialNumber, - LinkedBlockingQueue controllerQueue) { + LinkedBlockingQueue controllerQueue, + UIElement somethingWrongMessage) { super(requestId, ballotSerialNumber, controllerQueue); + this.somethingWrongMessage = somethingWrongMessage; } @Override @@ -27,6 +29,6 @@ public class WaitForFinishCallback extends ControllerCallback { logger.error("WaitForFinishCallback got a failure: " + t); enqueueCommand(new ReportErrorCommand(getRequestIdentifier(), getBallotSerialNumber(), - SystemMessages.getSomethingWrongMessage())); + somethingWrongMessage)); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index 074216f..d7e4508 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -1,13 +1,14 @@ package meerkat.voting.controller.commands; -import meerkat.protobuf.Voting.*; - +import meerkat.protobuf.Voting.BallotAnswer; import java.util.List; public class EncryptAndCommitBallotCommand extends ControllerCommand { private final List votingAnswers; - public EncryptAndCommitBallotCommand(int requestIdentifier, long ballotSerialNumber, List answers) { + public EncryptAndCommitBallotCommand(int requestIdentifier, + long ballotSerialNumber, + List answers) { super(requestIdentifier, ballotSerialNumber); votingAnswers = answers; } @@ -15,4 +16,5 @@ public class EncryptAndCommitBallotCommand extends ControllerCommand { public List getVotingAnswers() { return votingAnswers; } + } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java new file mode 100644 index 0000000..66dc992 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java @@ -0,0 +1,10 @@ +package meerkat.voting.controller.commands; + +public class RetryEncryptAndCommitBallotCommand extends EncryptAndCommitBallotCommand { + + public RetryEncryptAndCommitBallotCommand(int requestIdentifier, + long ballotSerialNumber) { + super(requestIdentifier, ballotSerialNumber, null); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index e664607..d5216e4 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -36,6 +36,7 @@ public interface VBCryptoManager { * @param plaintextBallot - all plaintext ballot info of the voter * @return an encryption of the ballot */ + // TODO: do we seed the random here? public EncryptionAndSecrets encrypt (PlaintextBallot plaintextBallot) throws SignatureException, IOException; diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 722c24e..2bc9729 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -52,6 +52,8 @@ public class VBCryptoManagerImpl implements VBCryptoManager { .setSignature(digitalSignature.sign()) .build(); + // TODO: still has to supply RandomnessGenerationProof as well + return new EncryptionAndSecrets(signedEncryptedBallot, secrets); } catch (IOException e) { diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index 9bf7764..b9ccca7 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -3,6 +3,7 @@ package meerkat.voting.storage; import meerkat.protobuf.Voting.*; import java.io.IOException; +import java.util.Map; /** * An interface for the storage component of the voting booth @@ -29,4 +30,20 @@ public interface StorageManager { */ public void writeElectionParams(ElectionParams params) throws IOException; + + public Map readSystemMessages() throws IOException; + + + public final static String WAIT_FOR_COMMIT_MESSAGE = "waitForCommit"; + public final static String WAIT_FOR_AUDIT_MESSAGE = "waitForAudit"; + public final static String WAIT_FOR_CAST_MESSAGE = "waitForCast"; + public final static String RESTART_VOTING_BUTTON = "restartVotingButton"; + public final static String UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE = "unrecognizedFinalizeResponse"; + public final static String UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE = "unsuccessfulChannelChoice"; + public final static String OUTPUT_DEVICE_FAILURE_MESSAGE = "outputDeviceFailure"; + public final static String UNSUCCESSFUL_VOTING_MESSAGE = "unsuccessfulVoting"; + public final static String SOMETHING_WRONG_MESSAGE = "somethingWrong"; + public final static String ENCRYPTION_FAILED_MESSAGE = "encryptionFailed"; + public final static String RETRY_BUTTON = "retryButton"; + public final static String CANCEL_VOTE_BUTTON = "cancelVoteButton"; } diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java index 23c89cf..ea9ac08 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -1,5 +1,6 @@ package meerkat.voting.storage; +import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -7,6 +8,8 @@ import org.slf4j.LoggerFactory; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * A mockup for the StorageManager interface @@ -16,7 +19,8 @@ public class StorageManagerMockup implements StorageManager { private boolean adminHardwareKeyInserted; private Logger logger; - private String electionParamFullFilename = "~/meerkat_election_params_tempfile.dat"; + public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; + public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; public StorageManagerMockup () { logger = LoggerFactory.getLogger(StorageManagerMockup.class); @@ -64,4 +68,23 @@ public class StorageManagerMockup implements StorageManager { } } + + @Override + public Map readSystemMessages() throws IOException { + + logger.info("Entered method readSystemMessages"); + BoothSystemMessages systemMessages; + try { + FileInputStream inputStream = new FileInputStream(systemMessagesFilename); + systemMessages = BoothSystemMessages.parseFrom(inputStream); + inputStream.close(); + logger.info ("Successfully read systemMessages protobuf from a file"); + } + catch (IOException e) { + logger.error("Could not read from the systemMessages file: '" + systemMessagesFilename + "'."); + throw e; + } + return systemMessages.getSystemMessage(); + } + } From 559c714aacda0248736abe05d2078de1db1ce91e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 20 Jun 2016 15:27:39 +0300 Subject: [PATCH 068/106] testing was changed according to the new interface of storage manager --- .../meerkat/voting/VotingBoothToyRun.java | 120 +++++++++++++++--- 1 file changed, 105 insertions(+), 15 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java index bf466f6..dfd9b6a 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -5,15 +5,14 @@ import meerkat.crypto.DigitalSignature; import meerkat.crypto.Encryption; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.*; -import meerkat.voting.controller.selector.SimpleListCategoriesSelector; import meerkat.voting.output.*; import meerkat.voting.storage.*; import meerkat.voting.encryptor.*; import meerkat.voting.ui.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; /** * Created by hai on 26/04/16. @@ -22,6 +21,14 @@ public class VotingBoothToyRun { public static void main(String[] args) { + try { + generateSystemMessages(); + generateDemoQuestions(); + } + catch (Exception e) { + return; + } + Random rand = new Random(); Encryption enc = new ToyEncryption(); DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); @@ -33,9 +40,15 @@ public class VotingBoothToyRun { VotingBoothImpl controller = new VotingBoothImpl(); - controller.init(outputDevice, cryptoManager, ui, storageManager); - generateDemoQuestions(controller); + try { + controller.init(outputDevice, cryptoManager, ui, storageManager); + } + catch (Exception e) { + System.err.println("init failed"); + return; + } + // create threads @@ -54,21 +67,29 @@ public class VotingBoothToyRun { } - private static void generateDemoQuestions(VotingBoothController controller) { + private static void generateDemoQuestions() throws IOException { - List channelChoiceQuestions = generateCahnnelChoiceQuestions(); - controller.setBallotChannelChoiceQuestions(channelChoiceQuestions); + ElectionParams electionParams = ElectionParams.newBuilder() + .addAllRaceQuestions(generateBallotQuestions()) + .addAllChannelChoiceQuestions(generateChannelChoiceQuestions()) + .setSelectionData(generateSelectionData()) + .build(); - List allBallotQuestions = generateBallotQuestions(); - controller.setBallotRaceQuestions(allBallotQuestions); + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.electionParamFullFilename); + electionParams.writeTo(output); + output.close(); + System.out.println("Successfully wrote election parameter protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the election parameter file: '" + StorageManagerMockup.electionParamFullFilename + "'."); + throw e; + } - SimpleCategoriesSelectionData selectionData = generateSelectionData(); - SimpleListCategoriesSelector selector = new SimpleListCategoriesSelector(allBallotQuestions, selectionData); - controller.setChannelQuestionSelector(selector); } - private static List generateCahnnelChoiceQuestions() { + private static List generateChannelChoiceQuestions() { ArrayList channelChoiceQuestions = new ArrayList(); String[] ans1 = {"Red", "Blue", "Green"}; @@ -192,9 +213,78 @@ public class VotingBoothToyRun { .build(); } + + + private static ByteString stringToBytes (String s) { return ByteString.copyFromUtf8(s); } + private static void generateSystemMessages() throws IOException{ + Map systemMessageMap = new HashMap(); + + systemMessageMap.put(StorageManager.WAIT_FOR_COMMIT_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_AUDIT_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_CAST_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build()); + systemMessageMap.put(StorageManager.RESTART_VOTING_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Restart voting")) + .build()); + systemMessageMap.put(StorageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_VOTING_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.SOMETHING_WRONG_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.ENCRYPTION_FAILED_MESSAGE, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Encryption failed for some unknown reason.")) + .build()); + systemMessageMap.put(StorageManager.RETRY_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Retry")) + .build()); + systemMessageMap.put(StorageManager.CANCEL_VOTE_BUTTON, UIElement.newBuilder() + .setType(UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Cancel Vote")) + .build()); + + BoothSystemMessages systemMessages = BoothSystemMessages.newBuilder().putAllSystemMessage(systemMessageMap).build(); + + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.systemMessagesFilename); + systemMessages.writeTo(output); + output.close(); + System.out.println("Successfully wrote system messages protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the system messages file: '" + StorageManagerMockup.systemMessagesFilename + "'."); + throw e; + } + + } } From 19deec00bbe2138d1220e72767df1edbdb0ef192 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 20 Jun 2016 16:15:41 +0300 Subject: [PATCH 069/106] a change of variable name to suggest its insignificance --- .../controller/callbacks/ErrorMessageRestartCallback.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java index 34f1194..fae8b4e 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -17,7 +17,7 @@ public class ErrorMessageRestartCallback extends ControllerCallback { } @Override - public void onSuccess(Integer result) { + public void onSuccess(Integer i) { enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } From e9732561f44562ae121ddd2819c09e8af3ea2947 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 21 Jun 2016 15:35:42 +0300 Subject: [PATCH 070/106] Removed the last dependency on the obsolete SystemMessages class. This dependency was left by mistake. We now read all the system messages of the VB from a protobuf file using the StorageManager component. --- .../voting/controller/SystemMessages.java | 77 ------------------- .../voting/controller/VotingBoothImpl.java | 2 +- 2 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java diff --git a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java b/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java deleted file mode 100644 index 4f57809..0000000 --- a/voting-booth/src/main/java/meerkat/voting/controller/SystemMessages.java +++ /dev/null @@ -1,77 +0,0 @@ -package meerkat.voting.controller; - -import com.google.protobuf.ByteString; -import meerkat.protobuf.Voting.*; - -/** - * Created by hai on 18/05/16. - */ -final public class SystemMessages { - - private SystemMessages() { - // This is a static class. No instantiation of this is needed. - } - - public static UIElement getWaitForCommitMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) - .build(); - } - - public static UIElement getWaitForAuditMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) - .build(); - } - - public static UIElement getWaitForCastMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) - .build(); - } - - public static UIElement getRestartVotingButton() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Restart voting")) - .build(); - } - - public static UIElement getUnrecognizedFinalizeResponseMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) - .build(); - } - - public static UIElement getUnsuccessfulChannelChoiceMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) - .build(); - } - - public static UIElement getOutputDeviceFailureMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) - .build(); - } - - public static UIElement getUnsuccessfulVotingMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) - .build(); - } - - public static UIElement getSomethingWrongMessage() { - return UIElement.newBuilder() - .setType(UIElementDataType.TEXT) - .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) - .build(); - } -} diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index b20a11d..849651f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -306,7 +306,7 @@ public class VotingBoothImpl implements VotingBoothController { systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { - ui.notifyVoterToWaitForFinish(SystemMessages.getWaitForCastMessage(), + ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, From 42ae18df0010a255c5e7d71f6aa50487b2c08d9c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 21 Jun 2016 15:37:20 +0300 Subject: [PATCH 071/106] Just added comments as part of the process to comment all the VB files. Currently I commented the controller callbacks and commands packages, and also the QuestionSelector component. --- .../callbacks/CastOrAuditCallback.java | 11 ++-- .../callbacks/ChannelChoiceCallback.java | 9 ++- .../callbacks/ControllerCallback.java | 12 ++-- .../callbacks/EncryptionFailedCallback.java | 18 +++--- .../ErrorMessageRestartCallback.java | 10 +++- .../callbacks/NewVoterCallback.java | 11 ++-- .../callbacks/OutputDeviceCommitCallback.java | 10 ++-- .../OutputDeviceFinalizeCallback.java | 10 ++-- .../callbacks/VoterCancelException.java | 4 +- .../controller/callbacks/VotingCallback.java | 13 ++-- .../callbacks/WaitForFinishCallback.java | 9 ++- .../controller/commands/AuditCommand.java | 2 +- .../controller/commands/CastCommand.java | 2 +- .../commands/ChannelChoiceCommand.java | 2 +- .../commands/ChannelDeterminedCommand.java | 2 +- .../commands/ChooseFinalizeOptionCommand.java | 2 +- .../commands/ControllerCommand.java | 4 ++ .../EncryptAndCommitBallotCommand.java | 4 ++ .../commands/ReportErrorCommand.java | 4 ++ .../commands/RestartVotingCommand.java | 3 + .../RetryEncryptAndCommitBallotCommand.java | 5 ++ .../controller/selector/QuestionSelector.java | 16 ++++- .../SimpleListCategoriesSelector.java | 59 +++++++++++++++++-- 23 files changed, 168 insertions(+), 54 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java index 47ecd3b..7226f83 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/CastOrAuditCallback.java @@ -2,13 +2,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.commands.*; -import meerkat.voting.controller.commands.ControllerCommand; import meerkat.voting.ui.VotingBoothUI.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the cast-or-audit request to the UI. + * Upon getting a FinalizeBallotChoice response from the voter, the callback then registers a new command + * to the controller queue, either a CastCommand or an AuditCommand according to the voter's choice + */ public class CastOrAuditCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(CastOrAuditCallback.class); protected final UIElement unrecognizedFinalizeResponseMessage; @@ -31,9 +34,7 @@ public class CastOrAuditCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(ChannelChoiceCallback.class); @@ -26,12 +29,14 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onSuccess(List result) { logger.debug("callback for channel choice returned success"); + // register the chosen BallotAnswers to a command in the controller queue enqueueCommand(new ChannelDeterminedCommand(getRequestIdentifier(), getBallotSerialNumber(), result)); } @Override public void onFailure(Throwable t) { if (t instanceof VoterCancelException) { + // voter has cancelled during the UI channel choice process. A VoterCancelException is thrown logger.debug("ChannelChoiceCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java index d5684d2..18719bd 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ControllerCallback.java @@ -1,13 +1,17 @@ package meerkat.voting.controller.callbacks; -/** - * Created by hai on 18/05/16. - */ import com.google.common.util.concurrent.FutureCallback; import meerkat.voting.controller.commands.ControllerCommand; - import java.util.concurrent.LinkedBlockingQueue; +/** + * The base (abstract) class of all callbacks for requests sent by the controller to other components (ui, output-device) + * It implements the FutureCallback interface + * Its members are: + * - requestIdentifier - uniquely identifies the request which this callback responds + * - ballotSerialNumber - number of ballot which was currently active when request was sent + * - controllerQueue - so the callback can issue and register a new command to the controller, once the request handling is finished + */ public abstract class ControllerCallback implements FutureCallback { private final int requestIdentifier; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java index de7a61e..55906be 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/EncryptionFailedCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; -import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; -import meerkat.voting.controller.commands.RetryEncryptAndCommitBallotCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This is quite a special callback. It is not issued in a normal flow of the voting. + * This callback is made only for a request to the UI to choose handling of failure in encryption. + * When encryption/signature fails the voter is asked in the UI whether to retry or abort. + * This specific callback decides, upon the answer to this request, which command to register in the controller's queue + */ public class EncryptionFailedCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(EncryptionFailedCallback.class); @@ -20,18 +22,18 @@ public class EncryptionFailedCallback extends ControllerCallback { @Override public void onSuccess(Integer result) { - logger.debug("callback for voting returned success"); + logger.debug("callback for encryption-failed request is initiated successfully"); int res = result.intValue(); if (res == 0) { logger.debug("voter chose to retry encryption"); enqueueCommand(new RetryEncryptAndCommitBallotCommand(getRequestIdentifier(), getBallotSerialNumber())); } else if (res == 1) { - logger.debug("voter chose to cancel the vote"); + logger.debug("voter chose to abort the vote"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } else { - onFailure(new ValueException("EncryptionFailedCallback got an unknown result (" + res + ")")); + onFailure(new IllegalArgumentException("EncryptionFailedCallback got an unknown result (" + res + ")")); } } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java index fae8b4e..4d75c1d 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ErrorMessageRestartCallback.java @@ -1,12 +1,16 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This is quite a special callback. It is not issued in a normal flow of the voting. + * This callback is made only for a request to the UI to show the voter an error message. + * Upon approval of the voter, the method onSuccess() of this callback is called, and the voting + * is reset through a command to the controller's queue + */ public class ErrorMessageRestartCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(ErrorMessageRestartCallback.class); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java index 9b4e365..17f67be 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/NewVoterCallback.java @@ -1,13 +1,16 @@ package meerkat.voting.controller.callbacks; -import meerkat.voting.controller.commands.ChannelChoiceCommand; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; + +/** + * A controller callback for the StartSession request to the UI. + * Upon approval of the voter, it registers a new ChannelChoiceCommand to the controller queue (which + * then starts the channel choice process) + */ public class NewVoterCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(NewVoterCallback.class); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java index a832572..dd20ec2 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceCommitCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ChooseFinalizeOptionCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the Commit request to the output-device. + * When committing is done, the callback's onSuccess() method is called to register a new ChooseFinalizeOptionCommand + * to the controller + */ public class OutputDeviceCommitCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceCommitCallback.class); protected final UIElement outputDeviceFailureMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java index 414bdb0..6c5b0d4 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/OutputDeviceFinalizeCallback.java @@ -1,14 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the Finalize request to the output-device. + * When finalizing (either cast or audit) is done, + * the callback's onSuccess() method is called to register a new command to the controller to restart the voting process + */ public class OutputDeviceFinalizeCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(OutputDeviceFinalizeCallback.class); protected final UIElement outputDeviceFailureMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java index 4c0d411..2844fc1 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java @@ -1,8 +1,8 @@ package meerkat.voting.controller.callbacks; /** - * Created by hai on 06/06/16. + * Just a simple unique exception to throw when a voter aborts/cancels the voting during the voting process */ -public class VoterCancelException extends Exception{ +public class VoterCancelException extends Exception { // } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index 173fa82..b389884 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -1,16 +1,19 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.EncryptAndCommitBallotCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; -import meerkat.voting.controller.commands.RestartVotingCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.List; import java.util.concurrent.LinkedBlockingQueue; +/** + * A controller callback for the race-voting request to the UI. + * Upon receiving the answers for the race questions, the callback registers a new command to process + * the voter's answers (encrypt and then commit) into the controller's queue. + * If voter cancelled during the process, a cancelling exception is thrown and a RestartVotingCommand is + * registered through the onFailure() method + */ public class VotingCallback extends ControllerCallback> { protected final static Logger logger = LoggerFactory.getLogger(VotingCallback.class); protected final UIElement unsuccessfulVotingMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java index 2634e27..f3f0308 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/WaitForFinishCallback.java @@ -1,13 +1,16 @@ package meerkat.voting.controller.callbacks; import meerkat.protobuf.Voting.UIElement; -import meerkat.voting.controller.commands.ControllerCommand; -import meerkat.voting.controller.commands.ReportErrorCommand; +import meerkat.voting.controller.commands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.concurrent.LinkedBlockingQueue; +/** + * This callback is attached to requests to UI which ask the voter to wait for some process to finish. + * It actually asks nothing in the UI, and it is simply attached to the UI request as a place-holder. + * Therefore its onSuccess() method is empty + */ public class WaitForFinishCallback extends ControllerCallback { protected final static Logger logger = LoggerFactory.getLogger(WaitForFinishCallback.class); protected final UIElement somethingWrongMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java index d2c99f2..fa7fc4a 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/AuditCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to audit the ballot */ public class AuditCommand extends ControllerCommand { public AuditCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java index 0621efb..c4e96bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/CastCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to cast the ballot */ public class CastCommand extends ControllerCommand { public CastCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java index f555e4b..9d86edb 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelChoiceCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to initiate the channel choice flow at the beginning of the voting */ public class ChannelChoiceCommand extends ControllerCommand { public ChannelChoiceCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java index 47d6f8b..c9b7023 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChannelDeterminedCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import java.util.List; /** - * Created by hai on 11/04/16. + * This command is registered in the controller right after the voter answered all the channel choice questions */ public class ChannelDeterminedCommand extends ControllerCommand { public List channelChoiceAnswers; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java index 76b0e77..0cdbacc 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ChooseFinalizeOptionCommand.java @@ -1,7 +1,7 @@ package meerkat.voting.controller.commands; /** - * Created by hai on 11/04/16. + * a command to initiate asking the voter how to finalize (cast-or-audit) the ballot */ public class ChooseFinalizeOptionCommand extends ControllerCommand { public ChooseFinalizeOptionCommand(int requestIdentifier, long ballotSerialNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java index 5bfc5c2..7743723 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ControllerCommand.java @@ -1,5 +1,9 @@ package meerkat.voting.controller.commands; +/** + * This is the base class for the controller commands. + * These commands are registered in a command queue of the controller. + */ public abstract class ControllerCommand { protected final int requestIdentifier; protected final long ballotSerialNumber; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java index d7e4508..3917a31 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/EncryptAndCommitBallotCommand.java @@ -3,6 +3,10 @@ package meerkat.voting.controller.commands; import meerkat.protobuf.Voting.BallotAnswer; import java.util.List; +/** + * a command registered after voter answered all ballot questions. + * The controller then initiates an encryption-signature-commit flow + */ public class EncryptAndCommitBallotCommand extends ControllerCommand { private final List votingAnswers; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java index b4a1fe7..fe3e369 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/ReportErrorCommand.java @@ -2,6 +2,10 @@ package meerkat.voting.controller.commands; import meerkat.protobuf.Voting.*; +/** + * This command is not a part of the normal flow of the controller. + * It asks the controller to handle (report to voter) some error message + */ public class ReportErrorCommand extends ControllerCommand { private final UIElement errorMessage; diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java index 57906d2..600a163 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RestartVotingCommand.java @@ -1,6 +1,9 @@ package meerkat.voting.controller.commands; +/** + * a command to restart a voting flow (for a new voter) + */ public class RestartVotingCommand extends ControllerCommand { public RestartVotingCommand(int requestIdentifier, long ballotSerialNumber) { super(requestIdentifier, ballotSerialNumber); diff --git a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java index 66dc992..b79a55f 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/commands/RetryEncryptAndCommitBallotCommand.java @@ -1,5 +1,10 @@ package meerkat.voting.controller.commands; +/** + * This is quite a special command not part of the normal voting flow. + * It extends the base EncryptAndCommitBallotCommand for occasions where first attempt of encryption failed + * and the voter asks to re-try encrypting and committing. + */ public class RetryEncryptAndCommitBallotCommand extends EncryptAndCommitBallotCommand { public RetryEncryptAndCommitBallotCommand(int requestIdentifier, diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java index e9decae..6603b62 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/QuestionSelector.java @@ -4,12 +4,26 @@ import meerkat.protobuf.Voting.*; import java.util.List; /** - * Created by hai on 02/05/16. + * An interface for the question-selection component. + * This component handles the connection between the channel choice questions and the race questions. + * It gets the answers for the channel choice questions and determines which race question to put in the voter's ballot. + * It also creates an identifier for this chosen channel. This identifier should appear in the plaintext of the ballot. + * The channel identifier does not identify a specific voter, but rather it identifies a specific voting channel */ public interface QuestionSelector { + /** + * determines an identifier for the channel of the voter + * @param channelChoiceAnswers The answers given by the voter to the channel choice questions + * @return an identifier of the channel. To be used by selectQuestionsForVoter(). This identifier should also appear on the plaintext of the ballot + */ public byte[] getChannelIdentifier (List channelChoiceAnswers); + /** + * determines which race questions to present to the voter according to its channel + * @param channelIdentifier the identifier of this specific channel + * @return the race questions (to present to the voter) + */ public List selectQuestionsForVoter (byte[] channelIdentifier); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 6181f05..7f2af87 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -11,28 +11,47 @@ import java.lang.Math; /** * A simple implementation of a QuestionSelector. * This implementation simply regards every single answer in the channel choice phase as an identifier of a category - * Every category is an array of ballot questions. + * Every category is an array of ballot race questions. * Data of categories is initialized and stored by a SimpleCategoriesSelectionData protobuf. * After receiving the answers from a channel choice phase, this class simply gathers all the categories * chosen and compiles the list of ballot questions to include in the ballot for this voter (a question - * is included if its index appears in any chosen category, or in the default category shared by all voters) + * is included in the ballot if its index appears in any chosen category, or in the default category shared by all voters) */ public class SimpleListCategoriesSelector implements QuestionSelector { protected final static Logger logger = LoggerFactory.getLogger(SimpleListCategoriesSelector.class); + // all the possible race questions private final BallotQuestion[] allBallotQuestions; + + // this category is presented to any voter (regardless of his answers to the channel choice questions) private final int[] sharedDefaults; + + // all the categories. + // first index is the channel choice question number + // second index is a possible answer to this question + // categoryChoosers[questionNumber][answerNumber] is an array of indices (to the ballotQuestions array). + // This category of questions is included in the ballot if voter answered this specific answer to this channel choice question private final int[][][] categoryChoosers; + private final static byte QUESTION_SELECTED = (byte)1; private final static byte QUESTION_NOT_SELECTED = (byte)0; - + /** + * A very straight-forward constructor for the SimpleListCategoriesSelector + * @param allBallotQuestions all possible race questions for this election + * @param data a protobuf containing all the index categories + */ public SimpleListCategoriesSelector(List allBallotQuestions, SimpleCategoriesSelectionData data) { + // copies the ballot race question list into a member array this.allBallotQuestions = new BallotQuestion[allBallotQuestions.size()]; allBallotQuestions.toArray(this.allBallotQuestions); + + // copies the shared category list (as appears in the protobuf data) into a member array sharedDefaults = listToIntArray(data.getSharedDefaults().getQuestionIndexList()); + + // copies the category lists (as appear in the protobuf data) into a 3-dimensional member array int[][][] selectionDataTmp = new int[data.getCategoryChooserList().size()][][]; int channelChoiceQuestionNumber = 0; for (CategoryChooser catChooser: data.getCategoryChooserList()) { @@ -45,12 +64,21 @@ public class SimpleListCategoriesSelector implements QuestionSelector { ++channelChoiceQuestionNumber; } categoryChoosers = selectionDataTmp; + + // verifies in advance that there are not very suspicious indices in the selection data assertDataValid(); } + /* + * asserts that the selection data does not contain a question index which is beyond the length of + * the ballot race questions array. Otherwise, throws an IndexOutOfBoundsException + */ private void assertDataValid () { - int questionsLength = allBallotQuestions.length; + // find the maximum question index in the selection data int maxQuestionIndex = -1; + for (int index: sharedDefaults) { + maxQuestionIndex = Math.max(maxQuestionIndex, index); + } for (int[][] categoryChooser: categoryChoosers) { for (int[] category: categoryChooser) { for (int index: category) { @@ -58,6 +86,9 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } } } + + // asserts that the maximal question index in the selection data does not overflow the ballot race questions array + int questionsLength = allBallotQuestions.length; if (maxQuestionIndex >= questionsLength) { String errorMessage = "Selection data refers to question index " + maxQuestionIndex + " while we have only " + questionsLength + " questions totally"; logger.error(errorMessage); @@ -66,8 +97,21 @@ public class SimpleListCategoriesSelector implements QuestionSelector { } + /** + * an implementation of the QuestionSelector interface method. + * In this selector class the identifier simply marks all the ballot race questions which appear in at least one + * category of the categories chosen by the voter (or in the shared defaults category) in the channel choice round. + * @param channelChoiceAnswers The answers given by the voter to the channel choice questions + * @return the channel identifier + */ @Override public byte[] getChannelIdentifier(List channelChoiceAnswers) { + /* + * Currently, this implementation of the QuestionSelector interface returns an over-simplified identifier which + * is merely an array of booleans (which flags the questions to appear in the ballot) + * For elections with more than one possible channel we should return a more printable and recognizable + * identifier to be put in the plaintext of the ballot + */ byte[] isSelected = new byte[allBallotQuestions.length]; java.util.Arrays.fill(isSelected, QUESTION_NOT_SELECTED); @@ -86,6 +130,10 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return isSelected; } + /* + * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). + * Otherwise, throws an exception. + */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { if (ballotAnswer.getAnswerCount() != 1) { String errorMessage = "SimpleListCategoriesSelector expects a single answer for every channel choice question\n"; @@ -109,6 +157,9 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return selectedQuestions; } + /* + * copies a List of Integers into an int[] array of same length + */ private int[] listToIntArray(List l) { int[] res = new int[l.size()]; int index = 0; From d1f7413cde83ef2dcad2a64f6b624674e6f94249 Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 26 Jun 2016 13:06:16 +0300 Subject: [PATCH 072/106] Working client-side Batch changes --- .../CachedBulletinBoardClient.java | 14 +- .../LocalBulletinBoardClient.java | 39 +-- .../SimpleBulletinBoardClient.java | 2 +- .../SimpleBulletinBoardSynchronizer.java | 79 +----- .../SingleServerBulletinBoardClient.java | 155 ++++------- .../ThreadedBulletinBoardClient.java | 7 +- .../MultiServerReadBatchDataWorker.java | 2 +- ...java => MultiServerReadMessageWorker.java} | 10 +- .../BulletinBoardSynchronizerTest.java | 63 +++-- .../GenericBulletinBoardClientTester.java | 252 ++++++++---------- .../GenericSubscriptionClientTester.java | 8 +- .../LocalBulletinBoardClientTest.java | 7 - ...dedBulletinBoardClientIntegrationTest.java | 7 - .../sqlserver/BulletinBoardSQLServer.java | 30 ++- .../AsyncBulletinBoardClient.java | 11 +- .../bulletinboard/BulletinBoardClient.java | 9 +- 16 files changed, 292 insertions(+), 403 deletions(-) rename bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/{MultiServerReadBatchWorker.java => MultiServerReadMessageWorker.java} (56%) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index 31521e1..6594b0c 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -3,9 +3,7 @@ package meerkat.bulletinboard; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; -import meerkat.protobuf.Comm; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Voting.*; @@ -267,9 +265,9 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public void readBatch(final MessageID msgID, final FutureCallback callback) { + public void readMessage(final MessageID msgID, final FutureCallback callback) { - localClient.readBatch(msgID, new FutureCallback() { + localClient.readMessage(msgID, new FutureCallback() { @Override public void onSuccess(BulletinBoardMessage result) { @@ -282,7 +280,7 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien // Read from local unsuccessful: try to read from remote - remoteClient.readBatch(msgID, new FutureCallback() { + remoteClient.readMessage(msgID, new FutureCallback() { @Override public void onSuccess(BulletinBoardMessage result) { @@ -398,17 +396,17 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { + public BulletinBoardMessage readMessage(MessageID msgID) throws CommunicationException { BulletinBoardMessage result = null; try { - result = localClient.readBatch(msgID); + result = localClient.readMessage(msgID); } catch (CommunicationException e) { //TODO: log } if (result == null){ - result = remoteClient.readBatch(msgID); + result = remoteClient.readMessage(msgID); if (result != null){ localClient.postMessage(result); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java index f09b2d3..2b904ed 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/LocalBulletinBoardClient.java @@ -183,6 +183,8 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } + batchId.setLength(i); + return true; } @@ -244,6 +246,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() .setBatchId(identifier.getBatchId().getValue()) + .setBatchLength(identifier.getLength()) .setTimestamp(timestamp) .addAllSig(signatures) .build(); @@ -438,7 +441,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo @Override public BulletinBoardMessage call() throws Exception { - // Read message stub + // Read message (mat be a stub) MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() @@ -451,19 +454,25 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo List bulletinBoardMessages = messageReader.call(); if (bulletinBoardMessages.size() <= 0) { - throw new NotFoundException("Batch does not exist"); + throw new NotFoundException("Message does not exist"); } - BulletinBoardMessage stub = bulletinBoardMessages.get(0); + BulletinBoardMessage msg = bulletinBoardMessages.get(0); - // Read data + if (msg.getMsg().getDataTypeCase() == UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { - BatchDataReader batchDataReader = new BatchDataReader(msgID); - List batchChunkList = batchDataReader.call(); + // Read data - // Combine and return + BatchDataReader batchDataReader = new BatchDataReader(msgID); + List batchChunkList = batchDataReader.call(); - return BulletinBoardUtils.gatherBatch(stub, batchChunkList); + // Combine and return + + return BulletinBoardUtils.gatherBatch(msg, batchChunkList); + + } else { + return msg; + } } @@ -493,7 +502,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public void readBatch(MessageID msgID, FutureCallback callback) { + public void readMessage(MessageID msgID, FutureCallback callback) { Futures.addCallback(executorService.submit(new CompleteBatchReader(msgID)), callback); } @@ -591,7 +600,7 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo } @Override - public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { + public BulletinBoardMessage readMessage(MessageID msgID) throws CommunicationException { MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() @@ -617,20 +626,14 @@ public class LocalBulletinBoardClient implements DeletableSubscriptionBulletinBo throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); } - MessageID msgID = MessageID.newBuilder().setID(stub.getMsg().getMsgId()).build(); - - BatchDataReader batchDataReader = new BatchDataReader(msgID); - - List batchChunkList = null; + BatchDataCombiner combiner = new BatchDataCombiner(stub); try { - batchChunkList = batchDataReader.call(); + return combiner.call(); } catch (Exception e) { throw new CommunicationException(e.getCause() + " " + e.getMessage()); } - return BulletinBoardUtils.gatherBatch(stub, batchChunkList); - } @Override diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 6250784..521815d 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -224,7 +224,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ } @Override - public BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException { + public BulletinBoardMessage readMessage(MessageID msgID) throws CommunicationException { MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java index e8abf6b..5cdf73b 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardSynchronizer.java @@ -36,75 +36,6 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize private Semaphore semaphore; - /** - * This class is a callback that deletes a message if it has been successfully posted - * It also calls a stored callback - */ - private class MessageDeleteCallback implements FutureCallback { - - private final long entryNum; - private final FutureCallback callback; - - public MessageDeleteCallback(long entryNum, FutureCallback callback) { - this.entryNum = entryNum; - this.callback = callback; - } - - @Override - public void onSuccess(Boolean result) { - // Success: delete from database - localClient.deleteMessage(entryNum, null); - callback.onSuccess(null); - } - - @Override - public void onFailure(Throwable t) { - callback.onFailure(t); - } - - } - - /** - * This class aggregates the results from all of the post operations - * If any post has failed: it changes the sync status to SERVER_ERROR - * It also notifies the main sync loop when all uploads are finished - */ - private class SyncStatusUpdateCallback implements FutureCallback { - - private int count; - private boolean errorEncountered; - - public SyncStatusUpdateCallback(int count) { - this.count = count; - this.errorEncountered = false; - } - - private void handleStatusUpdate() { - count--; - if (count <= 0) { - - if (errorEncountered) - updateSyncStatus(SyncStatus.SERVER_ERROR); - - // Upload is done: wake up the synchronizer loop - semaphore.release(); - - } - } - - @Override - public void onSuccess(Void result) { - handleStatusUpdate(); - } - - @Override - public void onFailure(Throwable t) { - errorEncountered = true; - handleStatusUpdate(); - } - - } - private class SyncCallback implements FutureCallback> { @Override @@ -122,8 +53,6 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize // Handle upload and status change - SyncStatusUpdateCallback syncStatusUpdateCallback = new SyncStatusUpdateCallback(result.size()); - SyncStatus newStatus = SyncStatus.PENDING; if (result.size() == 0) { @@ -143,13 +72,17 @@ public class SimpleBulletinBoardSynchronizer implements BulletinBoardSynchronize BulletinBoardMessage completeMsg = localClient.readBatchData(message); - remoteClient.postMessage(completeMsg, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); + remoteClient.postMessage(completeMsg); + + localClient.deleteMessage(completeMsg.getEntryNum()); } else { // This is a regular message: post it - remoteClient.postMessage(message, new MessageDeleteCallback(message.getEntryNum(), syncStatusUpdateCallback)); + remoteClient.postMessage(message); + + localClient.deleteMessage(message.getEntryNum()); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index b985a8a..86ede70 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -7,6 +7,8 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Int64Value; import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.singleserver.*; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.BulletinBoardClientParams; @@ -166,91 +168,74 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } } + private class ReadBatchCallback implements FutureCallback> { + + private final BulletinBoardMessage stub; + private final FutureCallback callback; + + public ReadBatchCallback(BulletinBoardMessage stub, FutureCallback callback) { + this.stub = stub; + this.callback = callback; + } + + @Override + public void onSuccess(List result) { + callback.onSuccess(BulletinBoardUtils.gatherBatch(stub, result)); + } + + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); + } + + } + /** - * This callback ties together the different parts of a CompleteBatch as they arrive from the server - * It assembles a CompleteBatch from the parts and sends it to the user if all parts arrived - * If any part fails to arrive: it invokes the onFailure method + * This callback receives a message which may be a stub + * If the message is not a stub: it returns it as is to a callback function + * If it is a stub: it schedules a read of the batch data which will return a complete message to the callback function */ - class CompleteBatchReadCallback { + class CompleteMessageReadCallback implements FutureCallback>{ private final FutureCallback callback; - private List batchChunkList; - private BulletinBoardMessage stub; - - private AtomicInteger remainingQueries; - private AtomicBoolean failed; - - public CompleteBatchReadCallback(FutureCallback callback) { + public CompleteMessageReadCallback(FutureCallback callback) { this.callback = callback; - remainingQueries = new AtomicInteger(2); - failed = new AtomicBoolean(false); - } - protected void combineAndReturn() { + @Override + public void onSuccess(List result) { + if (result.size() <= 0) { + onFailure(new CommunicationException("Could not find required message on the server.")); + } else { - if (remainingQueries.decrementAndGet() == 0){ + BulletinBoardMessage msg = result.get(0); - if (callback != null) - callback.onSuccess(BulletinBoardUtils.gatherBatch(stub, batchChunkList)); - } + if (msg.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { + callback.onSuccess(msg); + } else { - } + // Create job with MAX retries for retrieval of the Batch Data List - protected void fail(Throwable t) { - if (failed.compareAndSet(false, true)) { - if (callback != null) - callback.onFailure(t); + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(MessageID.newBuilder() + .setID(msg.getMsg().getMsgId()) + .build()) + .build(); + + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); + + scheduleWorker(batchWorker, new ReadBatchCallback(msg, callback)); + + } } } - /** - * @return a FutureCallback for the Batch Data List that ties to this object - */ - public FutureCallback> asBatchDataListFutureCallback() { - return new FutureCallback>() { - - @Override - public void onSuccess(List result) { - batchChunkList = result; - - combineAndReturn(); - } - - @Override - public void onFailure(Throwable t) { - fail(t); - } - - }; - } - - /** - * @return a FutureCallback for the Bulletin Board Message that ties to this object - */ - public FutureCallback> asBulletinBoardMessageListFutureCallback() { - return new FutureCallback>() { - - @Override - public void onSuccess(List result) { - if (result.size() < 1){ - onFailure(new IllegalArgumentException("Server returned empty message list")); - return; - } - - stub = result.get(0); - - combineAndReturn(); - } - - @Override - public void onFailure(Throwable t) { - fail(t); - } - }; + @Override + public void onFailure(Throwable t) { + callback.onFailure(t); } } @@ -574,9 +559,9 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } @Override - public void readBatch(MessageID msgID, FutureCallback callback) { + public void readMessage(MessageID msgID, FutureCallback callback) { - // Create job with MAX retries for retrieval of the Bulletin Board Message that defines the batch + // Create job with MAX retries for retrieval of the Bulletin Board Message (which may be a stub) MessageFilterList filterList = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() @@ -592,39 +577,11 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, MAX_RETRIES); - // Create job with MAX retries for retrieval of the Batch Data List - SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); - - // Create callback that will combine the two worker products - CompleteBatchReadCallback completeBatchReadCallback = new CompleteBatchReadCallback(callback); - // Submit jobs with wrapped callbacks - scheduleWorker(messageWorker, new RetryCallback<>(messageWorker, completeBatchReadCallback.asBulletinBoardMessageListFutureCallback())); - scheduleWorker(batchWorker, new RetryCallback<>(batchWorker, completeBatchReadCallback.asBatchDataListFutureCallback())); + scheduleWorker(messageWorker, new RetryCallback<>(messageWorker, new CompleteMessageReadCallback(callback))); } - private class ReadBatchCallback implements FutureCallback> { - - private final BulletinBoardMessage stub; - private final FutureCallback callback; - - public ReadBatchCallback(BulletinBoardMessage stub, FutureCallback callback) { - this.stub = stub; - this.callback = callback; - } - - @Override - public void onSuccess(List result) { - callback.onSuccess(BulletinBoardUtils.gatherBatch(stub, result)); - } - - @Override - public void onFailure(Throwable t) { - - } - } - @Override public void readBatchData(BulletinBoardMessage stub, FutureCallback callback) throws IllegalArgumentException{ diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 7f8232f..5c1cab4 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -4,7 +4,6 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.multiserver.*; -import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Voting.*; @@ -208,11 +207,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void readBatch(MessageID msgID, FutureCallback callback) { + public void readMessage(MessageID msgID, FutureCallback callback) { //Create job - MultiServerReadBatchWorker worker = - new MultiServerReadBatchWorker(clients, minAbsoluteRedundancy, msgID, READ_MESSAGES_RETRY_NUM, callback); + MultiServerReadMessageWorker worker = + new MultiServerReadMessageWorker(clients, minAbsoluteRedundancy, msgID, READ_MESSAGES_RETRY_NUM, callback); // Submit job executorService.submit(worker); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java index 959c60f..ab5fd40 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java @@ -22,7 +22,7 @@ public class MultiServerReadBatchDataWorker extends MultiServerGenericReadWorker @Override protected void doRead(MessageID payload, SingleServerBulletinBoardClient client) { - client.readBatch(payload, this); + client.readMessage(payload, this); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessageWorker.java similarity index 56% rename from bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java rename to bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessageWorker.java index 59b4ce5..f84d67e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadMessageWorker.java @@ -11,11 +11,11 @@ import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker { +public class MultiServerReadMessageWorker extends MultiServerGenericReadWorker { - public MultiServerReadBatchWorker(List clients, - int minServers, MessageID payload, int maxRetry, - FutureCallback futureCallback) { + public MultiServerReadMessageWorker(List clients, + int minServers, MessageID payload, int maxRetry, + FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); @@ -23,7 +23,7 @@ public class MultiServerReadBatchWorker extends MultiServerGenericReadWorker 0) { - for (Throwable t : thrown) - System.err.println(t.getMessage()); - assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), false); - } - } @After public void close() { + if (thrown.size() > 0) { + for (Throwable t : thrown) { + System.err.println(t.getMessage()); + } + assertThat("Exception thrown by Synchronizer: " + thrown.get(0).getMessage(), false); + } + synchronizer.stop(); localClient.close(); remoteClient.close(); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java index fa708d5..5e60957 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java @@ -5,9 +5,13 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; import meerkat.comm.CommunicationException; import meerkat.crypto.concrete.ECDSASignature; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto; import meerkat.util.BulletinBoardMessageComparator; +import meerkat.util.BulletinBoardMessageGenerator; +import meerkat.util.BulletinBoardUtils; +import meerkat.bulletinboard.AsyncBulletinBoardClient.BatchIdentifier; import java.io.IOException; import java.io.InputStream; @@ -27,7 +31,7 @@ public class GenericBulletinBoardClientTester { // Signature resources - private GenericBatchDigitalSignature signers[]; + private BulletinBoardSignature signers[]; private ByteString[] signerIDs; private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; @@ -48,13 +52,15 @@ public class GenericBulletinBoardClientTester { private RedundancyCallback redundancyCallback; private ReadCallback readCallback; - private ReadBatchCallback readBatchCallback; // Sync and misc private Semaphore jobSemaphore; private Vector thrown; private Random random; + private BulletinBoardMessageGenerator generator; + + private BulletinBoardDigest digest; // Constructor @@ -62,10 +68,10 @@ public class GenericBulletinBoardClientTester { this.bulletinBoardClient = bulletinBoardClient; - signers = new GenericBatchDigitalSignature[2]; + signers = new GenericBulletinBoardSignature[2]; signerIDs = new ByteString[signers.length]; - signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); - signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[0] = new GenericBulletinBoardSignature(new ECDSASignature()); + signers[1] = new GenericBulletinBoardSignature(new ECDSASignature()); InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); char[] password = KEYFILE_PASSWORD1.toCharArray(); @@ -107,6 +113,10 @@ public class GenericBulletinBoardClientTester { fail("Couldn't find signing key " + e.getMessage()); } + this.random = new Random(0); + this.generator = new BulletinBoardMessageGenerator(random); + this.digest = new GenericBulletinBoardDigest(new SHA256Digest()); + } // Callback definitions @@ -137,16 +147,21 @@ public class GenericBulletinBoardClientTester { @Override public void onSuccess(Boolean msg) { + System.err.println("Post operation completed"); - jobSemaphore.release(); - //TODO: Change Assert mechanism to exception one + if (isAssert) { - if (assertValue) { - assertThat("Post operation failed", msg, is(Boolean.TRUE)); + if (assertValue && !msg) { + genericHandleFailure(new AssertionError("Post operation failed")); + } else if (!assertValue && msg){ + genericHandleFailure(new AssertionError("Post operation succeeded unexpectedly")); } else { - assertThat("Post operation succeeded unexpectedly", msg, is(Boolean.FALSE)); + jobSemaphore.release(); } + } else { + jobSemaphore.release(); } + } @Override @@ -209,21 +224,24 @@ public class GenericBulletinBoardClientTester { } } - private class ReadBatchCallback implements FutureCallback { + private class ReadBatchCallback implements FutureCallback{ - private CompleteBatch expectedBatch; + private BulletinBoardMessage expectedMsg; - public ReadBatchCallback(CompleteBatch expectedBatch) { - this.expectedBatch = expectedBatch; + public ReadBatchCallback(BulletinBoardMessage expectedMsg) { + this.expectedMsg = expectedMsg; } @Override - public void onSuccess(CompleteBatch batch) { + public void onSuccess(BulletinBoardMessage msg) { - System.err.println(batch); - jobSemaphore.release(); + BulletinBoardMessageComparator msgComparator = new BulletinBoardMessageComparator(); - assertThat("Batch returned is incorrect", batch, is(equalTo(expectedBatch))); + if (msgComparator.compare(msg, expectedMsg) != 0) { + genericHandleFailure(new AssertionError("Batch read returned different message.\nExpected:" + expectedMsg + "\nRecieved:" + msg + "\n")); + } else { + jobSemaphore.release(); + } } @@ -233,59 +251,6 @@ public class GenericBulletinBoardClientTester { } } - // Randomness generators - - private byte randomByte(){ - return (byte) random.nextInt(); - } - - private byte[] randomByteArray(int length) { - - byte[] randomBytes = new byte[length]; - - for (int i = 0; i < length ; i++){ - randomBytes[i] = randomByte(); - } - - return randomBytes; - - } - - private CompleteBatch createRandomBatch(int signer, int batchId, int length) throws SignatureException { - - CompleteBatch completeBatch = new CompleteBatch(); - - // Create data - - completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder() - .setSignerId(signerIDs[signer]) - .setBatchId(batchId) - .addTag("Test") - .build()); - - for (int i = 0 ; i < length ; i++){ - - BatchChunk batchChunk = BatchChunk.newBuilder() - .setData(ByteString.copyFrom(randomByteArray(i))) - .build(); - - completeBatch.appendBatchData(batchChunk); - - } - - completeBatch.setTimestamp(Timestamp.newBuilder() - .setSeconds(Math.abs(90)) - .setNanos(50) - .build()); - - signers[signer].updateContent(completeBatch); - - completeBatch.setSignature(signers[signer].sign()); - - return completeBatch; - - } - // Test methods /** @@ -310,7 +275,13 @@ public class GenericBulletinBoardClientTester { public void close() { if (thrown.size() > 0) { + + for (Throwable t : thrown){ + System.err.println(t.getMessage()); + } + assert false; + } } @@ -394,59 +365,54 @@ public class GenericBulletinBoardClientTester { /** * Tests posting a batch by parts - * Also tests not being able to post to a closed batch * @throws CommunicationException, SignatureException, InterruptedException */ public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { - final int SIGNER = 1; - final int BATCH_ID = 100; final int BATCH_LENGTH = 100; + final int CHUNK_SIZE = 10; + final int TAG_NUM = 10; - CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); + final BulletinBoardMessage msg = generator.generateRandomMessage(signers, BATCH_LENGTH, TAG_NUM); // Begin batch - bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), postCallback); + bulletinBoardClient.beginBatch(msg.getMsg().getTagList(), new FutureCallback() { + + @Override + public void onSuccess(final BatchIdentifier identifier) { + + bulletinBoardClient.postBatchData(identifier, BulletinBoardUtils.breakToBatch(msg, CHUNK_SIZE), new FutureCallback() { + + @Override + public void onSuccess(Boolean result) { + + bulletinBoardClient.closeBatch(identifier, msg.getMsg().getTimestamp(), msg.getSigList(), postCallback); + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + + }); + + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + + }); jobSemaphore.acquire(); - // Post data + digest.reset(); + digest.update(msg); - bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), postCallback); - - jobSemaphore.acquire(); - - // Close batch - - CloseBatchMessage closeBatchMessage = completeBatch.getCloseBatchMessage(); - - bulletinBoardClient.closeBatch(closeBatchMessage, postCallback); - - jobSemaphore.acquire(); - - // Attempt to open batch again - - bulletinBoardClient.beginBatch(completeBatch.getBeginBatchMessage(), failPostCallback); - - // Attempt to add batch data - - bulletinBoardClient.postBatchData(signerIDs[SIGNER], BATCH_ID, completeBatch.getBatchDataList(), failPostCallback); - - jobSemaphore.acquire(2); - - // Read batch data - - BatchSpecificationMessage batchSpecificationMessage = - BatchSpecificationMessage.newBuilder() - .setSignerId(signerIDs[SIGNER]) - .setBatchId(BATCH_ID) - .setStartPosition(0) - .build(); - - readBatchCallback = new ReadBatchCallback(completeBatch); - - bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + bulletinBoardClient.readMessage(digest.digestAsMessageID(), new ReadBatchCallback(msg)); jobSemaphore.acquire(); @@ -454,62 +420,56 @@ public class GenericBulletinBoardClientTester { /** * Posts a complete batch message - * Checks reading of the message + * Checks reading of the message in two parts * @throws CommunicationException, SignatureException, InterruptedException */ public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { - final int SIGNER = 0; - final int BATCH_ID = 101; - final int BATCH_LENGTH = 50; + final int BATCH_LENGTH = 100; + final int CHUNK_SIZE = 99; + final int TAG_NUM = 8; + + final BulletinBoardMessage msg = generator.generateRandomMessage(signers, BATCH_LENGTH, TAG_NUM); // Post batch - CompleteBatch completeBatch = createRandomBatch(SIGNER, BATCH_ID, BATCH_LENGTH); - - bulletinBoardClient.postBatch(completeBatch,postCallback); + MessageID msgID = bulletinBoardClient.postAsBatch(msg, CHUNK_SIZE, postCallback); jobSemaphore.acquire(); // Read batch - BatchSpecificationMessage batchSpecificationMessage = - BatchSpecificationMessage.newBuilder() - .setSignerId(signerIDs[SIGNER]) - .setBatchId(BATCH_ID) - .setStartPosition(0) - .build(); + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) + .build()) + .build(); - readBatchCallback = new ReadBatchCallback(completeBatch); + bulletinBoardClient.readMessages(filterList, new FutureCallback>() { - bulletinBoardClient.readBatch(batchSpecificationMessage, readBatchCallback); + @Override + public void onSuccess(List msgList) { - jobSemaphore.acquire(); + if (msgList.size() != 1) { - } + genericHandleFailure(new AssertionError("Wrong number of stubs returned. Expected: 1; Found: " + msgList.size())); - /** - * Tests that an unopened batch cannot be closed - * @throws CommunicationException, InterruptedException - */ - public void testInvalidBatchClose() throws CommunicationException, InterruptedException { + } else { - final int NON_EXISTENT_BATCH_ID = 999; + BulletinBoardMessage retrievedMsg = msgList.get(0); + bulletinBoardClient.readBatchData(retrievedMsg, new ReadBatchCallback(msg)); - CloseBatchMessage closeBatchMessage = - CloseBatchMessage.newBuilder() - .setBatchId(NON_EXISTENT_BATCH_ID) - .setBatchLength(1) - .setSig(Crypto.Signature.getDefaultInstance()) - .setTimestamp(Timestamp.newBuilder() - .setSeconds(9) - .setNanos(12) - .build()) - .build(); + } - // Try to stop the (unopened) batch; + } - bulletinBoardClient.closeBatch(closeBatchMessage, failPostCallback); + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + + }); jobSemaphore.acquire(); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java index 52da797..ea74885 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java @@ -23,7 +23,7 @@ import static org.junit.Assert.fail; */ public class GenericSubscriptionClientTester { - private GenericBatchDigitalSignature signers[]; + private BulletinBoardSignature signers[]; private ByteString[] signerIDs; private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12"; @@ -47,10 +47,10 @@ public class GenericSubscriptionClientTester { this.bulletinBoardClient = bulletinBoardClient; - signers = new GenericBatchDigitalSignature[2]; + signers = new BulletinBoardSignature[2]; signerIDs = new ByteString[signers.length]; - signers[0] = new GenericBatchDigitalSignature(new ECDSASignature()); - signers[1] = new GenericBatchDigitalSignature(new ECDSASignature()); + signers[0] = new GenericBulletinBoardSignature(new ECDSASignature()); + signers[1] = new GenericBulletinBoardSignature(new ECDSASignature()); InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE); char[] password = KEYFILE_PASSWORD1.toCharArray(); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index 0ab5c67..1804c77 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -100,13 +100,6 @@ public class LocalBulletinBoardClientTest { } - @Test - public void testInvalidBatchClose() throws CommunicationException, InterruptedException { - - clientTest.testInvalidBatchClose(); - - } - @Test public void testSubscription() throws SignatureException, CommunicationException { subscriptionTester.init(); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java index b69cf72..1a95e95 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java @@ -85,11 +85,4 @@ public class ThreadedBulletinBoardClientIntegrationTest { } - @Test - public void testInvalidBatchClose() throws CommunicationException, InterruptedException { - - clientTest.testInvalidBatchClose(); - - } - } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index dcea3e7..e9c910a 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -19,6 +19,7 @@ import meerkat.crypto.DigitalSignature; import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; +import meerkat.protobuf.Comm; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; @@ -546,9 +547,17 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ } + private void checkConnection() throws CommunicationException { + if (jdbcTemplate == null) { + throw new CommunicationException("DB connection not initialized"); + } + } + @Override public BoolValue postMessage(BulletinBoardMessage msg) throws CommunicationException { + checkConnection(); + // Perform a post, calculate the message ID and check the signature for authenticity if (postMessage(msg, null) != -1){ return BoolValue.newBuilder().setValue(true).build(); // Message was posted @@ -561,6 +570,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public BoolValue deleteMessage(MessageID msgID) throws CommunicationException { + checkConnection(); + String sql = sqlQueryProvider.getSQLString(QueryType.DELETE_MSG_BY_ID); Map namedParameters = new HashMap(); @@ -577,6 +588,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public BoolValue deleteMessage(long entryNum) throws CommunicationException { + checkConnection(); + String sql = sqlQueryProvider.getSQLString(QueryType.DELETE_MSG_BY_ENTRY); Map namedParameters = new HashMap(); @@ -702,6 +715,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public void readMessages(MessageFilterList filterList, MessageOutputStream out) throws CommunicationException { + checkConnection(); + BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); // SQL length is roughly 50 characters per filter + 50 for the query itself @@ -725,6 +740,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public Int32Value getMessageCount(MessageFilterList filterList) throws CommunicationException { + checkConnection(); + BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); // SQL length is roughly 50 characters per filter + 50 for the query itself @@ -793,6 +810,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public Int64Value beginBatch(BeginBatchMessage message) throws CommunicationException { + checkConnection(); + // Store tags String sql = sqlQueryProvider.getSQLString(QueryType.STORE_BATCH_TAGS); MapSqlParameterSource namedParameters = new MapSqlParameterSource(); @@ -814,6 +833,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public BoolValue postBatchMessage(BatchMessage batchMessage) throws CommunicationException{ + checkConnection(); + // Make sure batch is open if (!isBatchOpen(batchMessage.getBatchId())) { return BoolValue.newBuilder().setValue(false).build(); @@ -837,6 +858,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public BoolValue closeBatch(CloseBatchMessage message) throws CommunicationException { + checkConnection(); // Check batch size @@ -916,6 +938,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public void readBatch(BatchQuery batchQuery, MessageOutputStream out) throws CommunicationException, IllegalArgumentException{ + checkConnection(); + // Check that batch is closed if (!isBatchClosed(batchQuery.getMsgID())) { throw new IllegalArgumentException("No such batch"); @@ -950,7 +974,9 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ } @Override - public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) { + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException{ + + checkConnection(); if (generateSyncQueryParams == null || !generateSyncQueryParams.hasFilterList() @@ -1029,6 +1055,8 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ @Override public SyncQueryResponse querySync(SyncQuery syncQuery) throws CommunicationException { + checkConnection(); + if (syncQuery == null){ return SyncQueryResponse.newBuilder() .setLastEntryNum(-1) diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 42af8ef..ab71a76 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -87,19 +87,20 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * Read all messages posted matching the given filter in an asynchronous 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. + * are guaranteed to be included * Also: batch messages are returned as stubs. - * @param filterList return only messages that match the filters (null means no filtering). + * @param filterList return only messages that match the filters (null means no filtering) * @param callback is a callback function class for handling results of the operation */ public void readMessages(MessageFilterList filterList, FutureCallback> callback); /** - * Read a given batch message from the bulletin board - * @param msgID is the batch message ID to be read + * Read a given message from the bulletin board + * If the message is a batch: returns a complete message containing the batch data as well as the metadata + * @param msgID is the ID of the message to be read * @param callback is a callback class for handling the result of the operation */ - public void readBatch(MessageID msgID, FutureCallback callback); + public void readMessage(MessageID msgID, FutureCallback callback); /** * Read batch data for a specific stub message diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 142bb35..7f29608 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -55,12 +55,13 @@ public interface BulletinBoardClient { MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException; /** - * Read a given batch message from the bulletin board - * @param msgID is the batch message ID to be read - * @return the complete batch + * Read a given message from the bulletin board + * If the message is a batch: returns a complete message containing the batch data as well as the metadata + * @param msgID is the ID of the message to be read + * @return the complete message * @throws CommunicationException if operation is unsuccessful */ - BulletinBoardMessage readBatch(MessageID msgID) throws CommunicationException; + BulletinBoardMessage readMessage(MessageID msgID) throws CommunicationException; /** * Read batch data for a specific stub message From cc2888483de408b97b79e0b67bf5ec3ffe07306e Mon Sep 17 00:00:00 2001 From: Arbel Deutsch Peled Date: Sun, 26 Jun 2016 14:32:30 +0300 Subject: [PATCH 073/106] Threaded Client integration tests passing --- .../ThreadedBulletinBoardClient.java | 11 +++- .../MultiServerBeginBatchWorker.java | 2 +- .../MultiServerCloseBatchWorker.java | 60 +++++++++++++++++-- .../MultiServerPostBatchDataWorker.java | 2 +- .../SingleServerBeginBatchWorker.java | 7 ++- .../GenericBulletinBoardClientTester.java | 28 +++++++-- .../LocalBulletinBoardClientTest.java | 4 +- ...dedBulletinBoardClientIntegrationTest.java | 4 +- 8 files changed, 98 insertions(+), 20 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index 5c1cab4..b549a2e 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -160,11 +160,18 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple } @Override - public void closeBatch(BatchIdentifier payload, Timestamp timestamp, Iterable signatures, FutureCallback callback) { + public void closeBatch(BatchIdentifier payload, Timestamp timestamp, Iterable signatures, FutureCallback callback) + throws IllegalArgumentException{ + + if (!(payload instanceof MultiServerBatchIdentifier)) { + throw new IllegalArgumentException("Error: batch identifier supplied was not created by this class."); + } + + MultiServerBatchIdentifier identifier = (MultiServerBatchIdentifier) payload; // Create job MultiServerCloseBatchWorker worker = - new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, payload, timestamp, signatures, POST_MESSAGE_RETRY_NUM, callback); + new MultiServerCloseBatchWorker(clients, minAbsoluteRedundancy, identifier, timestamp, signatures, POST_MESSAGE_RETRY_NUM, callback); // Submit job executorService.submit(worker); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java index 793fc6e..7d64946 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerBeginBatchWorker.java @@ -46,7 +46,7 @@ public class MultiServerBeginBatchWorker extends MultiServerWorker { +public class MultiServerCloseBatchWorker extends MultiServerWorker { private final Timestamp timestamp; - private final Iterable signatures; + private final Iterable signatures; - public MultiServerCloseBatchWorker(List clients, int minServers, - BatchIdentifier payload, Timestamp timestamp, Iterable signatures, + public MultiServerCloseBatchWorker(List clients, + int minServers, MultiServerBatchIdentifier payload, Timestamp timestamp, Iterable signatures, int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); @@ -28,8 +34,50 @@ public class MultiServerCloseBatchWorker extends MultiServerGenericPostWorker identifierIterator = payload.getIdentifiers().iterator(); + + // Iterate through client + + for (SingleServerBulletinBoardClient client : clients) { + + if (identifierIterator.hasNext()) { + + // Fetch the batch identifier supplied by the specific client (may be null if batch open failed on client + + BatchIdentifier identifier = identifierIterator.next(); + + if (identifier != null) { + + // Post the data with the matching identifier to the client + client.closeBatch(identifier, timestamp, signatures, this); + + } else { + + // Count servers with no batch identifier as failed + maxFailedServers.decrementAndGet(); + + } + + } + + } + + } + + @Override + public void onSuccess(Boolean result) { + if (minServers.decrementAndGet() <= 0){ + succeed(result); + } + } + + @Override + public void onFailure(Throwable t) { + if (maxFailedServers.decrementAndGet() <= 0){ + fail(t); + } } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java index 052b625..8ef5931 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerPostBatchDataWorker.java @@ -40,7 +40,7 @@ public class MultiServerPostBatchDataWorker extends MultiServerWorker() { + @Override + public void onSuccess(Boolean result) { + jobSemaphore.release(); + } + + @Override + public void onFailure(Throwable t) { + genericHandleFailure(t); + } + }); } @@ -429,7 +444,12 @@ public class GenericBulletinBoardClientTester { final int CHUNK_SIZE = 99; final int TAG_NUM = 8; - final BulletinBoardMessage msg = generator.generateRandomMessage(signers, BATCH_LENGTH, TAG_NUM); + final Timestamp timestamp = Timestamp.newBuilder() + .setSeconds(7776151) + .setNanos(252616) + .build(); + + final BulletinBoardMessage msg = generator.generateRandomMessage(signers, timestamp, BATCH_LENGTH, TAG_NUM); // Post batch diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index 1804c77..56392d7 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -81,9 +81,9 @@ public class LocalBulletinBoardClientTest { } @Test - public void postTest() { + public void testPost() { - clientTest.postTest(); + clientTest.testPost(); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java index 1a95e95..dd47354 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java @@ -66,9 +66,9 @@ public class ThreadedBulletinBoardClientIntegrationTest { } @Test - public void postTest() { + public void testPost() { - clientTest.postTest(); + clientTest.testPost(); } From 06d69554d9d15317a26889e405e290b4ef6681f6 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 26 Jun 2016 17:07:03 +0300 Subject: [PATCH 074/106] fixed some merge conflicts which appeared for some unknown reason --- bulletin-board-server/build.gradle | 525 ++++++++++++++--------------- voting-booth/build.gradle | 384 +++++++++++---------- 2 files changed, 453 insertions(+), 456 deletions(-) diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 46ef4cf..766ed56 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -1,263 +1,262 @@ - -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 - } - } - } -} - - - + +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 + } + } + } +} + + diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 241e3c3..7619b48 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -1,193 +1,191 @@ - -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 = "Meerkat voting booth application" - -// 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 =======*/ - -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() - - // 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 = "Meerkat voting booth application" + +// 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 =======*/ + +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() + + // 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 + } + } + } +} + From 53d609bfee483c348f6d35396c817fa6aecc95d1 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Tue, 28 Jun 2016 08:19:29 +0300 Subject: [PATCH 075/106] Removed database address from Bulletin Board Server init method (the address is given to the Query Provider). Added integration tests for Single Server Bulletin Board Client. Fixed subscription logic in the Single Server Bulletin Board Client. Decoupled Single Server- and Simple- Bulletin Board Clients (Simple-... is now obsolete). Fixed some bugs. Threaded Bulletin Board Client now has some errors in integration. --- .../CachedBulletinBoardClient.java | 45 ++- .../SimpleBulletinBoardClient.java | 13 +- .../SingleServerBulletinBoardClient.java | 284 ++++++++++++++++-- .../ThreadedBulletinBoardSubscriber.java | 2 - .../SingleServerGenerateSyncQueryWorker.java | 55 ++++ .../BulletinBoardSynchronizerTest.java | 4 +- .../CachedBulletinBoardClientTest.java | 111 +++++++ .../GenericSubscriptionClientTester.java | 8 +- .../LocalBulletinBoardClientTest.java | 27 +- ...verBulletinBoardClientIntegrationTest.java | 104 +++++++ .../sqlserver/BulletinBoardSQLServer.java | 2 +- .../webapp/BulletinBoardWebApp.java | 10 +- .../H2BulletinBoardServerTest.java | 2 +- .../MySQLBulletinBoardServerTest.java | 2 +- .../SQLiteBulletinBoardServerTest.java | 2 +- .../bulletinboard/BulletinBoardClient.java | 3 +- .../bulletinboard/BulletinBoardServer.java | 2 +- 17 files changed, 575 insertions(+), 101 deletions(-) create mode 100644 bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenerateSyncQueryWorker.java create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java create mode 100644 bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java index 6594b0c..cdb86cb 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/CachedBulletinBoardClient.java @@ -23,12 +23,16 @@ import java.util.List; public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClient { private final AsyncBulletinBoardClient localClient; - private AsyncBulletinBoardClient remoteClient; - private BulletinBoardSubscriber subscriber; - private BulletinBoardSynchronizer synchronizer; + private final AsyncBulletinBoardClient remoteClient; + private final AsyncBulletinBoardClient queueClient; + private final BulletinBoardSubscriber subscriber; + private final BulletinBoardSynchronizer synchronizer; private Thread syncThread; + private final static int DEFAULT_WAIT_CAP = 3000; + private final static int DEFAULT_SLEEP_INTERVAL = 3000; + private class SubscriptionStoreCallback implements FutureCallback> { private final FutureCallback> callback; @@ -81,21 +85,36 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien * @param localClient is a Client for the local instance * @param remoteClient is a Client for the remote instance(s); Should have endless retries for post operations * @param subscriber is a subscription service to the remote instance(s) - * @param queue is a client for a local deletable server to be used as a queue for not-yet-uploaded messages + * @param queueClient is a client for a local deletable server to be used as a queue for not-yet-uploaded messages */ + public CachedBulletinBoardClient(AsyncBulletinBoardClient localClient, + AsyncBulletinBoardClient remoteClient, + BulletinBoardSubscriber subscriber, + DeletableSubscriptionBulletinBoardClient queueClient, + int sleepInterval, + int waitCap) { + + this.localClient = localClient; + this.remoteClient = remoteClient; + this.subscriber = subscriber; + this.queueClient = queueClient; + + this.synchronizer = new SimpleBulletinBoardSynchronizer(sleepInterval,waitCap); + synchronizer.init(queueClient, remoteClient); + syncThread = new Thread(synchronizer); + syncThread.start(); + } + + /** + * Creates a Cached Client + * Used default values foe the time caps + * */ public CachedBulletinBoardClient(AsyncBulletinBoardClient localClient, AsyncBulletinBoardClient remoteClient, BulletinBoardSubscriber subscriber, DeletableSubscriptionBulletinBoardClient queue) { - this.localClient = localClient; - this.remoteClient = remoteClient; - this.subscriber = subscriber; - - this.synchronizer = new SimpleBulletinBoardSynchronizer(); - synchronizer.init(queue, remoteClient); - syncThread = new Thread(synchronizer); - syncThread.start(); + this(localClient, remoteClient, subscriber, queue, DEFAULT_SLEEP_INTERVAL, DEFAULT_WAIT_CAP); } @Override @@ -385,7 +404,7 @@ public class CachedBulletinBoardClient implements SubscriptionBulletinBoardClien } @Override - public float getRedundancy(MessageID id) { + public float getRedundancy(MessageID id) throws CommunicationException { return remoteClient.getRedundancy(id); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java index 521815d..a274f53 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SimpleBulletinBoardClient.java @@ -68,16 +68,11 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{ // 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(BoolValue.class).getValue(); - } else { - throw new CommunicationException("Server returned error. Status was: " + response.getStatus()); - } + SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(db, msg, 0); + + worker.call(); + } } catch (Exception e) { // Occurs only when server replies with valid status but invalid data throw new CommunicationException("Error accessing database: " + e.getMessage()); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index 86ede70..be75dfe 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -8,15 +8,15 @@ import com.google.protobuf.Int64Value; import com.google.protobuf.Timestamp; import meerkat.bulletinboard.workers.singleserver.*; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI; +import meerkat.crypto.concrete.SHA256Digest; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.BulletinBoardClientParams; import meerkat.util.BulletinBoardUtils; +import javax.ws.rs.client.Client; import java.lang.Iterable; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -31,11 +31,17 @@ import java.util.concurrent.atomic.AtomicInteger; * If the list of servers contains more than one server: the server actually used is the first one * The class further implements a delayed access to the server after a communication error occurs */ -public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient implements SubscriptionBulletinBoardClient { +public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoardClient { + + protected Client client; + + protected BulletinBoardDigest digest; + + private String dbAddress; private final int MAX_RETRIES = 11; - private ListeningScheduledExecutorService executorService; + private final ListeningScheduledExecutorService executorService; private long lastServerErrorTime; @@ -54,6 +60,43 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i } + private class SynchronousRetry { + + private final SingleServerWorker worker; + + private String thrown; + + public SynchronousRetry(SingleServerWorker worker) { + this.worker = worker; + this.thrown = "Could not contact server. Errors follow:\n"; + } + + OUT run() throws CommunicationException { + + do { + + try { + return worker.call(); + } catch (Exception e) { + thrown += e.getCause() + " " + e.getMessage() + "\n"; + } + + try { + Thread.sleep(failDelayInMilliseconds); + } catch (InterruptedException e) { + //TODO: log + } + + worker.decMaxRetry(); + + } while (worker.isRetry()); + + throw new CommunicationException(thrown); + + } + + } + /** * This method adds a worker to the scheduled queue of the threadpool * If the server is in an accessible state: the job is submitted for immediate handling @@ -225,7 +268,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i .build()) .build(); - SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(dbAddress, batchQuery, MAX_RETRIES); scheduleWorker(batchWorker, new ReadBatchCallback(msg, callback)); @@ -266,20 +309,28 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i if (callback != null) callback.onSuccess(result); - // Remove last filter from list (MIN_ENTRY one) - filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); + // Update filter if needed - // Add updated MIN_ENTRY filter (entry number is successor of last received entry's number) - filterBuilder.addFilter(MessageFilter.newBuilder() - .setType(FilterType.MIN_ENTRY) - .setEntry(result.get(result.size() - 1).getEntryNum() + 1) - .build()); + if (result.size() > 0) { + + // Remove last filter from list (MIN_ENTRY one) + filterBuilder.removeFilter(filterBuilder.getFilterCount() - 1); + + // Add updated MIN_ENTRY filter (entry number is successor of last received entry's number) + filterBuilder.addFilter(MessageFilter.newBuilder() + .setType(FilterType.MIN_ENTRY) + .setEntry(result.get(result.size() - 1).getEntryNum() + 1) + .build()); + + } // Create new worker with updated task - worker = new SingleServerReadMessagesWorker(worker.serverAddress, filterBuilder.build(), 1); + worker = new SingleServerReadMessagesWorker(worker.serverAddress, filterBuilder.build(), MAX_RETRIES); - // Schedule the worker - scheduleWorker(worker, this); + RetryCallback> retryCallback = new RetryCallback<>(worker, this); + + // Schedule the worker to run after the given interval has elapsed + Futures.addCallback(executorService.schedule(worker, subscriptionIntervalInMilliseconds, TimeUnit.MILLISECONDS), retryCallback); } @@ -324,21 +375,192 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void init(BulletinBoardClientParams clientParams) { - // Perform usual setup - super.init(clientParams); + this.digest = new GenericBulletinBoardDigest(new SHA256Digest()); // Remove all but first DB address - String dbAddress = meerkatDBs.get(0); - meerkatDBs = new LinkedList<>(); - meerkatDBs.add(dbAddress); + this.dbAddress = clientParams.getBulletinBoardAddress(0); } + // Synchronous methods + + @Override + public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException { + + SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(dbAddress, msg, MAX_RETRIES); + + SynchronousRetry retry = new SynchronousRetry<>(worker); + + retry.run(); + + digest.reset(); + digest.update(msg); + + return digest.digestAsMessageID(); + + } + + @Override + public float getRedundancy(MessageID id) throws CommunicationException { + + SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(dbAddress, id, MAX_RETRIES); + + SynchronousRetry retry = new SynchronousRetry<>(worker); + + return retry.run(); + + } + + @Override + public List readMessages(MessageFilterList filterList) throws CommunicationException { + + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(dbAddress, filterList, MAX_RETRIES); + + SynchronousRetry> retry = new SynchronousRetry<>(worker); + + return retry.run(); + + } + + @Override + public MessageID postAsBatch(BulletinBoardMessage msg, int chunkSize) throws CommunicationException { + + // Begin the batch and obtain identifier + + BeginBatchMessage beginBatchMessage = BeginBatchMessage.newBuilder() + .addAllTag(msg.getMsg().getTagList()) + .build(); + + SingleServerBeginBatchWorker beginBatchWorker = new SingleServerBeginBatchWorker(dbAddress, beginBatchMessage, MAX_RETRIES); + + SynchronousRetry beginRetry = new SynchronousRetry<>(beginBatchWorker); + + Int64Value identifier = beginRetry.run(); + + // Post data chunks + + List batchChunkList = BulletinBoardUtils.breakToBatch(msg, chunkSize); + + BatchMessage.Builder builder = BatchMessage.newBuilder().setBatchId(identifier.getValue()); + + int position = 0; + + for (BatchChunk data : batchChunkList) { + + builder.setSerialNum(position).setData(data); + + SingleServerPostBatchWorker dataWorker = new SingleServerPostBatchWorker(dbAddress, builder.build(), MAX_RETRIES); + + SynchronousRetry dataRetry = new SynchronousRetry<>(dataWorker); + + dataRetry.run(); + + // Increment position in batch + position++; + + } + + // Close batch + + CloseBatchMessage closeBatchMessage = CloseBatchMessage.newBuilder() + .setBatchId(identifier.getValue()) + .addAllSig(msg.getSigList()) + .setTimestamp(msg.getMsg().getTimestamp()) + .setBatchLength(position) + .build(); + + SingleServerCloseBatchWorker closeBatchWorker = new SingleServerCloseBatchWorker(dbAddress, closeBatchMessage, MAX_RETRIES); + + SynchronousRetry retry = new SynchronousRetry<>(closeBatchWorker); + + retry.run(); + + // Calculate ID and return + + digest.reset(); + digest.update(msg); + + return digest.digestAsMessageID(); + + } + + @Override + public BulletinBoardMessage readMessage(MessageID msgID) throws CommunicationException { + + // Retrieve message (which may be a stub) + + MessageFilterList filterList = MessageFilterList.newBuilder() + .addFilter(MessageFilter.newBuilder() + .setType(FilterType.MSG_ID) + .setId(msgID.getID()) + .build()) + .build(); + + SingleServerReadMessagesWorker stubWorker = new SingleServerReadMessagesWorker(dbAddress, filterList, MAX_RETRIES); + + SynchronousRetry> retry = new SynchronousRetry<>(stubWorker); + + List messages = retry.run(); + + if (messages.size() <= 0) { + throw new CommunicationException("Could not find message in database."); + } + + BulletinBoardMessage msg = messages.get(0); + + if (msg.getMsg().getDataTypeCase() != UnsignedBulletinBoardMessage.DataTypeCase.MSGID) { + + // We retrieved a complete message. Return it. + return msg; + + } else { + + // We retrieved a stub. Retrieve data. + return readBatchData(msg); + + } + + } + + @Override + public BulletinBoardMessage readBatchData(BulletinBoardMessage stub) throws CommunicationException, IllegalArgumentException { + + BatchQuery batchQuery = BatchQuery.newBuilder() + .setMsgID(MessageID.newBuilder() + .setID(stub.getMsg().getMsgId()) + .build()) + .setStartPosition(0) + .build(); + + SingleServerReadBatchWorker readBatchWorker = new SingleServerReadBatchWorker(dbAddress, batchQuery, MAX_RETRIES); + + SynchronousRetry> batchRetry = new SynchronousRetry<>(readBatchWorker); + + List batchChunkList = batchRetry.run(); + + return BulletinBoardUtils.gatherBatch(stub, batchChunkList); + + } + + @Override + public SyncQuery generateSyncQuery(GenerateSyncQueryParams generateSyncQueryParams) throws CommunicationException { + + SingleServerGenerateSyncQueryWorker worker = + new SingleServerGenerateSyncQueryWorker(dbAddress, generateSyncQueryParams, MAX_RETRIES); + + SynchronousRetry retry = new SynchronousRetry<>(worker); + + return retry.run(); + + } + + // Asynchronous methods + @Override public MessageID postMessage(BulletinBoardMessage msg, FutureCallback callback) { // Create worker with redundancy 1 and MAX_RETRIES retries - SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(meerkatDBs.get(0), msg, MAX_RETRIES); + SingleServerPostMessageWorker worker = new SingleServerPostMessageWorker(dbAddress, msg, MAX_RETRIES); // Submit worker and create callback scheduleWorker(worker, new RetryCallback<>(worker, callback)); @@ -453,7 +675,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerBeginBatchWorker worker = - new SingleServerBeginBatchWorker(meerkatDBs.get(0), beginBatchMessage, MAX_RETRIES); + new SingleServerBeginBatchWorker(dbAddress, beginBatchMessage, MAX_RETRIES); // Submit worker and create callback scheduleWorker(worker, new RetryCallback<>(worker, new BeginBatchCallback(callback))); @@ -491,7 +713,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerPostBatchWorker worker = - new SingleServerPostBatchWorker(meerkatDBs.get(0), builder.build(), MAX_RETRIES); + new SingleServerPostBatchWorker(dbAddress, builder.build(), MAX_RETRIES); // Create worker with redundancy 1 and MAX_RETRIES retries scheduleWorker(worker, new RetryCallback<>(worker, listCallback)); @@ -529,7 +751,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i // Create worker with redundancy 1 and MAX_RETRIES retries SingleServerCloseBatchWorker worker = - new SingleServerCloseBatchWorker(meerkatDBs.get(0), closeBatchMessage, MAX_RETRIES); + new SingleServerCloseBatchWorker(dbAddress, closeBatchMessage, MAX_RETRIES); // Submit worker and create callback scheduleWorker(worker, new RetryCallback<>(worker, callback)); @@ -540,7 +762,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void getRedundancy(MessageID id, FutureCallback callback) { // Create worker with no retries - SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(meerkatDBs.get(0), id, 1); + SingleServerGetRedundancyWorker worker = new SingleServerGetRedundancyWorker(dbAddress, id, 1); // Submit job and create callback scheduleWorker(worker, new RetryCallback<>(worker, callback)); @@ -551,7 +773,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i public void readMessages(MessageFilterList filterList, FutureCallback> callback) { // Create job with no retries - SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, 1); + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(dbAddress, filterList, 1); // Submit job and create callback scheduleWorker(worker, new RetryCallback<>(worker, callback)); @@ -575,7 +797,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i .setStartPosition(0) .build(); - SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterList, MAX_RETRIES); + SingleServerReadMessagesWorker messageWorker = new SingleServerReadMessagesWorker(dbAddress, filterList, MAX_RETRIES); // Submit jobs with wrapped callbacks scheduleWorker(messageWorker, new RetryCallback<>(messageWorker, new CompleteMessageReadCallback(callback))); @@ -598,7 +820,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i .setStartPosition(0) .build(); - SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(meerkatDBs.get(0), batchQuery, MAX_RETRIES); + SingleServerReadBatchWorker batchWorker = new SingleServerReadBatchWorker(dbAddress, batchQuery, MAX_RETRIES); scheduleWorker(batchWorker, new RetryCallback<>(batchWorker, new ReadBatchCallback(stub, callback))); @@ -607,7 +829,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void querySync(SyncQuery syncQuery, FutureCallback callback) { - SingleServerQuerySyncWorker worker = new SingleServerQuerySyncWorker(meerkatDBs.get(0), syncQuery, MAX_RETRIES); + SingleServerQuerySyncWorker worker = new SingleServerQuerySyncWorker(dbAddress, syncQuery, MAX_RETRIES); scheduleWorker(worker, new RetryCallback<>(worker, callback)); @@ -633,7 +855,7 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i .build()); // Create job with no retries - SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(meerkatDBs.get(0), filterListBuilder.build(), MAX_RETRIES); + SingleServerReadMessagesWorker worker = new SingleServerReadMessagesWorker(dbAddress, filterListBuilder.build(), MAX_RETRIES); // Submit job and create callback that retries on failure and handles repeated subscription scheduleWorker(worker, new RetryCallback<>(worker, new SubscriptionCallback(worker, callback))); @@ -647,8 +869,6 @@ public class SingleServerBulletinBoardClient extends SimpleBulletinBoardClient i @Override public void close() { - super.close(); - executorService.shutdown(); } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java index 9568255..252d6e3 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardSubscriber.java @@ -250,7 +250,6 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber super(filterList, callback); } - @Override public void onSuccess(List result) { @@ -274,5 +273,4 @@ public class ThreadedBulletinBoardSubscriber implements BulletinBoardSubscriber subscribe(filterList, 0, callback); } - } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenerateSyncQueryWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenerateSyncQueryWorker.java new file mode 100644 index 0000000..71d90e0 --- /dev/null +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/singleserver/SingleServerGenerateSyncQueryWorker.java @@ -0,0 +1,55 @@ +package meerkat.bulletinboard.workers.singleserver; + +import com.google.protobuf.Int64Value; +import meerkat.bulletinboard.SingleServerWorker; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.BulletinBoardAPI.SyncQuery; +import meerkat.protobuf.BulletinBoardAPI.GenerateSyncQueryParams; +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.GENERATE_SYNC_QUERY_PATH; + +/** + * Created by Arbel Deutsch Peled on 27-Dec-15. + * Tries to contact server once and perform a Sync Query Generation operation + */ +public class SingleServerGenerateSyncQueryWorker extends SingleServerWorker { + + public SingleServerGenerateSyncQueryWorker(String serverAddress, GenerateSyncQueryParams payload, int maxRetry) { + super(serverAddress, payload, maxRetry); + } + + @Override + public SyncQuery call() throws Exception { + + Client client = clientLocal.get(); + + WebTarget webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(GENERATE_SYNC_QUERY_PATH); + + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF)); + + try { + + SyncQuery result = response.readEntity(SyncQuery.class); + return result; + + } catch (ProcessingException | IllegalStateException e) { + + // Post to this server failed + throw new CommunicationException("Could not contact the server. Original error: " + e.getMessage()); + + } catch (Exception e) { + throw new CommunicationException("Could not contact the server. Original error: " + e.getMessage()); + } + finally { + response.close(); + } + } +} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java index 588f529..19e7ae5 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/BulletinBoardSynchronizerTest.java @@ -114,7 +114,7 @@ public class BulletinBoardSynchronizerTest { public void init() throws CommunicationException { DeletableBulletinBoardServer remoteServer = new BulletinBoardSQLServer(new H2QueryProvider(REMOTE_SERVER_ADDRESS + testCount)); - remoteServer.init(REMOTE_SERVER_ADDRESS); + remoteServer.init(); remoteClient = new LocalBulletinBoardClient( remoteServer, @@ -122,7 +122,7 @@ public class BulletinBoardSynchronizerTest { SUBSCRIPTION_INTERVAL); DeletableBulletinBoardServer localServer = new BulletinBoardSQLServer(new H2QueryProvider(LOCAL_SERVER_ADDRESS + testCount)); - localServer.init(LOCAL_SERVER_ADDRESS); + localServer.init(); localClient = new LocalBulletinBoardClient( localServer, diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java new file mode 100644 index 0000000..83e62ff --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java @@ -0,0 +1,111 @@ +package meerkat.bulletinboard; + +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; +import meerkat.bulletinboard.sqlserver.H2QueryProvider; +import meerkat.comm.CommunicationException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.security.SignatureException; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Arbel on 6/27/2016. + */ +public class CachedBulletinBoardClientTest { + + private static final int THREAD_NUM = 3; + + private static final String LOCAL_DB_NAME = "localDB"; + private static final String REMOTE_DB_NAME = "remoteDB"; + private static final String QUEUE_DB_NAME = "queueDB"; + + private static final int SUBSRCIPTION_DELAY = 500; + private static final int SYNC_DELAY = 500; + + // Testers + private CachedBulletinBoardClient cachedClient; + private GenericBulletinBoardClientTester clientTest; + private GenericSubscriptionClientTester subscriptionTester; + + public CachedBulletinBoardClientTest() throws CommunicationException { + + DeletableBulletinBoardServer localServer = new BulletinBoardSQLServer(new H2QueryProvider(LOCAL_DB_NAME)); + localServer.init(); + LocalBulletinBoardClient localClient = new LocalBulletinBoardClient(localServer, THREAD_NUM, SUBSRCIPTION_DELAY); + + DeletableBulletinBoardServer remoteServer = new BulletinBoardSQLServer(new H2QueryProvider(REMOTE_DB_NAME)); + remoteServer.init(); + LocalBulletinBoardClient remoteClient = new LocalBulletinBoardClient(remoteServer, THREAD_NUM, SUBSRCIPTION_DELAY); + + DeletableBulletinBoardServer queueServer = new BulletinBoardSQLServer(new H2QueryProvider(QUEUE_DB_NAME)); + queueServer.init(); + LocalBulletinBoardClient queueClient = new LocalBulletinBoardClient(queueServer, THREAD_NUM, SUBSRCIPTION_DELAY); + + List clientList = new LinkedList<>(); + clientList.add(remoteClient); + + BulletinBoardSubscriber subscriber = new ThreadedBulletinBoardSubscriber(clientList, localClient); + + cachedClient = new CachedBulletinBoardClient(localClient, remoteClient, subscriber, queueClient, SYNC_DELAY, SYNC_DELAY); + subscriptionTester = new GenericSubscriptionClientTester(cachedClient); + clientTest = new GenericBulletinBoardClientTester(cachedClient); + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + @Before + public void init(){ + + clientTest.init(); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + @After + public void close() { + + cachedClient.close(); + clientTest.close(); + + } + + @Test + public void testPost() { + + clientTest.testPost(); + + } + + @Test + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testBatchPost(); + } + + @Test + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testCompleteBatchPost(); + + } + + @Test + public void testSubscription() throws SignatureException, CommunicationException { + +// subscriptionTester.init(); +// subscriptionTester.subscriptionTest(); +// subscriptionTester.close(); + + } + +} diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java index ea74885..6d02914 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericSubscriptionClientTester.java @@ -178,7 +178,7 @@ public class GenericSubscriptionClientTester { public void onFailure(Throwable t) { System.err.println(t.getCause() + " " + t.getMessage()); thrown.add(t); - jobSemaphore.release(expectedMessages.size()); + jobSemaphore.release(); stage = expectedMessages.size(); } } @@ -202,9 +202,9 @@ public class GenericSubscriptionClientTester { .build(); List> expectedMessages = new ArrayList<>(3); - expectedMessages.add(new LinkedList()); - expectedMessages.add(new LinkedList()); - expectedMessages.add(new LinkedList()); + expectedMessages.add(new LinkedList<>()); + expectedMessages.add(new LinkedList<>()); + expectedMessages.add(new LinkedList<>()); expectedMessages.get(0).add(msg1); expectedMessages.get(2).add(msg3); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index 56392d7..9ee1d60 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -7,12 +7,6 @@ import org.junit.Before; import org.junit.Test; import java.security.SignatureException; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; - -import static org.junit.Assert.fail; /** * Created by Arbel Deutsch Peled on 05-Dec-15. @@ -30,26 +24,10 @@ public class LocalBulletinBoardClientTest { public LocalBulletinBoardClientTest() throws CommunicationException { - H2QueryProvider queryProvider = new H2QueryProvider(DB_NAME) ; - - try { - - Connection conn = queryProvider.getDataSource().getConnection(); - Statement stmt = conn.createStatement(); - - List deletionQueries = queryProvider.getSchemaDeletionCommands(); - - for (String deletionQuery : deletionQueries) { - stmt.execute(deletionQuery); - } - - } catch (SQLException e) { - System.err.println(e.getMessage()); - throw new CommunicationException(e.getCause() + " " + e.getMessage()); - } + H2QueryProvider queryProvider = new H2QueryProvider(DB_NAME); DeletableBulletinBoardServer server = new BulletinBoardSQLServer(queryProvider); - server.init(DB_NAME); + server.init(); LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM, SUBSRCIPTION_DELAY); subscriptionTester = new GenericSubscriptionClientTester(client); @@ -102,6 +80,7 @@ public class LocalBulletinBoardClientTest { @Test public void testSubscription() throws SignatureException, CommunicationException { + subscriptionTester.init(); subscriptionTester.subscriptionTest(); subscriptionTester.close(); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java new file mode 100644 index 0000000..424c4c5 --- /dev/null +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java @@ -0,0 +1,104 @@ +package meerkat.bulletinboard; + +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import meerkat.comm.CommunicationException; +import meerkat.protobuf.Voting.BulletinBoardClientParams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.security.SignatureException; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executors; + +/** + * Created by Arbel Deutsch Peled on 05-Dec-15. + */ +public class SingleServerBulletinBoardClientIntegrationTest { + + // Server data + + private static final String PROP_GETTY_URL = "gretty.httpBaseURI"; + private static final String DEFAULT_BASE_URL = "http://localhost:8081"; + private static final String BASE_URL = System.getProperty(PROP_GETTY_URL, DEFAULT_BASE_URL); + + private static final int THREAD_NUM = 3; + private static final long FAIL_DELAY = 3000; + private static final long SUBSCRIPTION_INTERVAL = 500; + + // Testers + private GenericBulletinBoardClientTester clientTest; + private GenericSubscriptionClientTester subscriptionTester; + + public SingleServerBulletinBoardClientIntegrationTest(){ + + SingleServerBulletinBoardClient client = new SingleServerBulletinBoardClient(THREAD_NUM, FAIL_DELAY, SUBSCRIPTION_INTERVAL); + + List testDB = new LinkedList<>(); + testDB.add(BASE_URL); + + client.init(BulletinBoardClientParams.newBuilder() + .addAllBulletinBoardAddress(testDB) + .setMinRedundancy((float) 1.0) + .build()); + + clientTest = new GenericBulletinBoardClientTester(client); + subscriptionTester = new GenericSubscriptionClientTester(client); + + } + + // Test methods + + /** + * Takes care of initializing the client and the test resources + */ + @Before + public void init(){ + + clientTest.init(); + + } + + /** + * Closes the client and makes sure the test fails when an exception occurred in a separate thread + */ + + @After + public void close() { + + clientTest.close(); + + } + + @Test + public void testPost() { + + clientTest.testPost(); + + } + + @Test + public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testBatchPost(); + } + + @Test + public void testCompleteBatchPost() throws CommunicationException, SignatureException, InterruptedException { + + clientTest.testCompleteBatchPost(); + + } + + @Test + public void testSubscription() throws SignatureException, CommunicationException { + + subscriptionTester.init(); + subscriptionTester.subscriptionTest(); + subscriptionTester.close(); + + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index e9c910a..bf99259 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -368,7 +368,7 @@ public class BulletinBoardSQLServer implements DeletableBulletinBoardServer{ * This method initializes the signatures, connects to the DB and creates the schema (if required). */ @Override - public void init(String meerkatDB) throws CommunicationException { + public void init() throws CommunicationException { // TODO write signature reading part. digest = new GenericBulletinBoardDigest(new SHA256Digest()); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index f9d3a94..8e9d161 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -44,14 +44,6 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL 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(); @@ -77,7 +69,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL } try { - init(dbName); + bulletinBoard.init(); servletContext.setAttribute(BULLETIN_BOARD_ATTRIBUTE_NAME, bulletinBoard); } catch (CommunicationException e) { System.err.println(e.getMessage()); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java index fa96635..def0b41 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -54,7 +54,7 @@ public class H2BulletinBoardServerTest { BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider); try { - bulletinBoardServer.init(""); + bulletinBoardServer.init(); } catch (CommunicationException e) { System.err.println(e.getMessage()); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java index 334620c..abc0fc6 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -58,7 +58,7 @@ public class MySQLBulletinBoardServerTest { BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider); try { - bulletinBoardServer.init(""); + bulletinBoardServer.init(); } catch (CommunicationException e) { System.err.println(e.getMessage()); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java index 4dcd97b..18278b3 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java @@ -39,7 +39,7 @@ public class SQLiteBulletinBoardServerTest{ BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(new SQLiteQueryProvider(testFilename)); try { - bulletinBoardServer.init(""); + bulletinBoardServer.init(); } catch (CommunicationException e) { System.err.println(e.getMessage()); diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index 7f29608..c03051c 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -31,8 +31,9 @@ public interface BulletinBoardClient { * 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) + * @throws CommunicationException */ - float getRedundancy(MessageID id); + float getRedundancy(MessageID id) throws CommunicationException; /** * Read all messages posted matching the given filter in a synchronous manner diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index 8121b85..40f8ab3 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -22,7 +22,7 @@ public interface BulletinBoardServer{ * It also establishes the connection to the DB * @throws CommunicationException on DB connection error */ - public void init(String meerkatDB) throws CommunicationException; + public void init() throws CommunicationException; /** * Post a message to bulletin board. From 437992144565027adb04c8185fcc264bad88cc17 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:26:00 +0300 Subject: [PATCH 076/106] For some reason restful API did not appear in my gradle.build. It is fixed now. --- voting-booth/build.gradle | 1 + ...ception.java => VoterCancelThrowable.java} | 2 +- .../output/AsyncRunnableOutputDevice.java | 161 ++++++++++++++++++ .../voting/output/NetworkVirtualPrinter.java | 37 ++++ 4 files changed, 200 insertions(+), 1 deletion(-) rename voting-booth/src/main/java/meerkat/voting/controller/callbacks/{VoterCancelException.java => VoterCancelThrowable.java} (76%) create mode 100644 voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java create mode 100644 voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 7619b48..ef89f86 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -40,6 +40,7 @@ version += "${isSnapshot ? '-SNAPSHOT' : ''}" dependencies { // Meerkat common compile project(':meerkat-common') + compile project(':restful-api-common') // Logging compile 'org.slf4j:slf4j-api:1.7.7' diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java similarity index 76% rename from voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java rename to voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java index 2844fc1..38c2c8b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelException.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VoterCancelThrowable.java @@ -3,6 +3,6 @@ package meerkat.voting.controller.callbacks; /** * Just a simple unique exception to throw when a voter aborts/cancels the voting during the voting process */ -public class VoterCancelException extends Exception { +public class VoterCancelThrowable extends Throwable { // } diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java new file mode 100644 index 0000000..50bd6d5 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -0,0 +1,161 @@ +package meerkat.voting.output; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.BoolValue; +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.protobuf.Voting.*; +import meerkat.rest.*; +import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.output.outputcommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.*; +import javax.ws.rs.core.Response; + +import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { + + private Logger logger; + private LinkedBlockingQueue queue; + private volatile boolean shutDownHasBeenCalled; + + private SignedEncryptedBallot signedEncryptedBallot; + + private final WebTarget successfulPrintTarget; + + public AsyncRunnableOutputDevice(String address) { + logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); + logger.info("A NetworkVirtualPrinter is constructed"); + queue = new LinkedBlockingQueue<>(); + shutDownHasBeenCalled = false; + + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + } + + @Override + public void run () { + logger.info("starts running"); + while (! wasShutDownCalled()) { + try { + OutputCommand command = queue.take(); + handleSingleCommand(command); + } + catch (InterruptedException e) { + logger.warn ("Interrupted while reading from command queue " + e); + } + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + queue.clear(); + } + + + private void handleSingleCommand(OutputCommand command) { + if (command instanceof CommitOutputCommand) { + doCommitToBallot((CommitOutputCommand)command); + } + else if (command instanceof AuditOutputCommand) { + doAudit((AuditOutputCommand)command); + } + else if (command instanceof CastOutputCommand) { + doCastBallot((CastOutputCommand)command); + } + else if (command instanceof CancelOutputCommand) { + doCancel((CancelOutputCommand)command); + } + else { + String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + + @Override + public void commitToBallot(PlaintextBallot plaintextBallot, + SignedEncryptedBallot signedEncryptedBallot, + FutureCallback callback) { + logger.debug("Output interface call to commit to ballot"); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + } + + @Override + public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { + logger.debug("an interface call to audit"); + queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + } + + @Override + public void castBallot(FutureCallback callback) { + logger.debug("an interface call to cast ballot"); + queue.add(new CastOutputCommand((ControllerCallback)callback)); + } + + @Override + public void cancelBallot(FutureCallback callback) { + logger.debug("an interface call to cancel the output"); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); + } + + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + signedEncryptedBallot = command.getSignedEncryptedBallot(); + command.getCallback().onSuccess(null); + } + + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + + + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setSignedEncryptedBallot(this.signedEncryptedBallot) + .build(); + + Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + BoolValue b = response.readEntity(BoolValue.class); + response.close(); + + if (b.getValue()) { + command.getCallback().onSuccess(null); + } + else { + command.getCallback().onFailure(new IOException()); + } + } + + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java new file mode 100644 index 0000000..d3e3625 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -0,0 +1,37 @@ +package meerkat.voting.output; + +import com.google.protobuf.BoolValue; +import meerkat.pollingstation.PollingStationScanner; +import meerkat.protobuf.PollingStation.*; +import meerkat.rest.*; + +import javax.ws.rs.client.*; + +import static meerkat.pollingstation.PollingStationConstants.*; + +/** + * Created by hai on 27/06/16. + */ +public class NetworkVirtualPrinter implements PollingStationScanner.Producer { + + WebTarget successfulScanPath; + WebTarget errorPath; + + public NetworkVirtualPrinter(String address) { + Client client = ClientBuilder.newClient(); + client.register(ProtobufMessageBodyReader.class); + client.register(ProtobufMessageBodyWriter.class); + successfulScanPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + errorPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + } + + @Override + public BoolValue newScan(ScannedData scannedData) { + return null; + } + + @Override + public BoolValue reportScanError(ErrorMsg errorMsg) { + return null; + } +} From 438df78e368a308e8ab1167764509d9180f2724c Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:26:50 +0300 Subject: [PATCH 077/106] Changed the ToySignature test file to match the new Signature interface. --- .../src/main/java/meerkat/voting/ToySignature.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/ToySignature.java b/voting-booth/src/main/java/meerkat/voting/ToySignature.java index e2473c9..8b24a3c 100644 --- a/voting-booth/src/main/java/meerkat/voting/ToySignature.java +++ b/voting-booth/src/main/java/meerkat/voting/ToySignature.java @@ -4,13 +4,11 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Message; import meerkat.crypto.DigitalSignature; import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.Crypto.Signature; import java.io.IOException; import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; +import java.security.*; import java.security.cert.CertificateException; /** @@ -69,6 +67,11 @@ public class ToySignature implements DigitalSignature { throw new UnsupportedOperationException(); } + @Override + public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException { + throw new UnsupportedOperationException(); + } + @Override public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException { throw new UnsupportedOperationException(); From 3a5908ac49976634fa3c786f33300500accadc15 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:28:14 +0300 Subject: [PATCH 078/106] A cancel by the voter is now sent to the execution flow as a Throwable rather than an Exception. --- .../controller/callbacks/ChannelChoiceCallback.java | 4 ++-- .../voting/controller/callbacks/VotingCallback.java | 2 +- .../src/main/java/meerkat/voting/ui/SystemConsoleUI.java | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java index a87fe0a..7b97a82 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/ChannelChoiceCallback.java @@ -35,8 +35,8 @@ public class ChannelChoiceCallback extends ControllerCallback @Override public void onFailure(Throwable t) { - if (t instanceof VoterCancelException) { - // voter has cancelled during the UI channel choice process. A VoterCancelException is thrown + if (t instanceof VoterCancelThrowable) { + // voter has cancelled during the UI channel choice process. A VoterCancelThrowable is thrown logger.debug("ChannelChoiceCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java index b389884..96c940b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/callbacks/VotingCallback.java @@ -34,7 +34,7 @@ public class VotingCallback extends ControllerCallback> { @Override public void onFailure(Throwable t) { - if (t instanceof VoterCancelException) { + if (t instanceof VoterCancelThrowable) { logger.debug("VotingCallback got a cancellation response"); enqueueCommand(new RestartVotingCommand(getRequestIdentifier(), getBallotSerialNumber())); } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index bc3ac92..b8a3828 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -155,7 +155,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } - catch (VoterCancelException e) { + catch (VoterCancelThrowable e) { command.getCallback().onFailure(e); } catch (IOException e) { @@ -179,7 +179,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { List answers = askVoterForAnswers(command.getQuestions()); command.getCallback().onSuccess(answers); } - catch (VoterCancelException e) { + catch (VoterCancelThrowable e) { command.getCallback().onFailure(e); } catch (IOException e) { @@ -339,7 +339,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } - private List askVoterForAnswers(List questions) throws VoterCancelException, IOException { + private List askVoterForAnswers(List questions) throws VoterCancelThrowable, IOException { assertQuestionsAreValid (questions); @@ -354,7 +354,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { String s = readInputLine(); if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { - throw new VoterCancelException(); + throw new VoterCancelThrowable(); } else if (s.equals("back") || s.equals("b")) { --index; From 14fac728b3e816500e5b45e11a02ebcac56e0f66 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:32:00 +0300 Subject: [PATCH 079/106] 1. ScannedData now has a Channel and a SignedEncryptedBallot attributes, rather than just 'data' attribute 2. Implemented a NetworkVirtualPrinter output device, and now both this class and the previous SystemConsoleOutputDevice extend the same new abstract class AsyncRunnableOutputDevice which supplies default implementations for the interface methods. --- .../main/proto/meerkat/PollingStation.proto | 7 +- .../PollingStationWebScannerTest.java | 6 +- .../output/AsyncRunnableOutputDevice.java | 77 +++------------ .../voting/output/NetworkVirtualPrinter.java | 79 ++++++++++++--- .../output/SystemConsoleOutputDevice.java | 98 ++----------------- 5 files changed, 98 insertions(+), 169 deletions(-) diff --git a/meerkat-common/src/main/proto/meerkat/PollingStation.proto b/meerkat-common/src/main/proto/meerkat/PollingStation.proto index 0cdc658..09596a5 100644 --- a/meerkat-common/src/main/proto/meerkat/PollingStation.proto +++ b/meerkat-common/src/main/proto/meerkat/PollingStation.proto @@ -2,11 +2,16 @@ syntax = "proto3"; package meerkat; +import "meerkat/voting.proto"; + option java_package = "meerkat.protobuf"; // Container for scanned data message ScannedData { - bytes data = 1; + bytes channel = 1; + + SignedEncryptedBallot signed_encrypted_ballot = 2; + } // Container for error messages diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index 7da106c..e94c633 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -2,7 +2,9 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; +import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.PollingStation.*; +import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; import meerkat.rest.*; @@ -46,7 +48,7 @@ public class PollingStationWebScannerTest { @Override public void onSuccess(ScannedData result) { - dataIsAsExpected = result.getData().equals(expectedData.getData()); + dataIsAsExpected = result.getChannel().equals(expectedData.getChannel()); semaphore.release(); } @@ -109,7 +111,7 @@ public class PollingStationWebScannerTest { byte[] data = {(byte) 1, (byte) 2}; ScannedData scannedData = ScannedData.newBuilder() - .setData(ByteString.copyFrom(data)) + .setChannel(ByteString.copyFrom(data)) .build(); scanner.subscribe(new ScanHandler(scannedData)); diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 50bd6d5..d4620bb 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -1,46 +1,30 @@ package meerkat.voting.output; import com.google.common.util.concurrent.FutureCallback; -import com.google.protobuf.BoolValue; -import meerkat.protobuf.PollingStation.ScannedData; -import meerkat.protobuf.Voting.*; -import meerkat.rest.*; +import meerkat.protobuf.Voting.BallotSecrets; +import meerkat.protobuf.Voting.PlaintextBallot; +import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.voting.controller.callbacks.ControllerCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.*; -import javax.ws.rs.core.Response; - -import java.io.IOException; import java.util.concurrent.LinkedBlockingQueue; -import static meerkat.pollingstation.PollingStationConstants.*; - /** * Created by hai on 27/06/16. */ -public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { +public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; private LinkedBlockingQueue queue; private volatile boolean shutDownHasBeenCalled; - private SignedEncryptedBallot signedEncryptedBallot; - - private final WebTarget successfulPrintTarget; - - public AsyncRunnableOutputDevice(String address) { + public AsyncRunnableOutputDevice() { logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); - logger.info("A NetworkVirtualPrinter is constructed"); + logger.info("AsyncRunnableOutputDevice is constructed"); queue = new LinkedBlockingQueue<>(); shutDownHasBeenCalled = false; - - Client client = ClientBuilder.newClient(); - client.register(ProtobufMessageBodyReader.class); - client.register(ProtobufMessageBodyWriter.class); - successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); } @Override @@ -69,6 +53,15 @@ public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable } + abstract void doCommitToBallot(CommitOutputCommand command); + + abstract void doAudit(AuditOutputCommand command); + + abstract void doCastBallot(CastOutputCommand command); + + abstract void doCancel(CancelOutputCommand command); + + private void handleSingleCommand(OutputCommand command) { if (command instanceof CommitOutputCommand) { doCommitToBallot((CommitOutputCommand)command); @@ -118,44 +111,4 @@ public class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable } - public void doCommitToBallot(CommitOutputCommand command) { - logger.debug("entered method doCommitToBallot"); - signedEncryptedBallot = command.getSignedEncryptedBallot(); - command.getCallback().onSuccess(null); - } - - - public void doAudit(AuditOutputCommand command) { - logger.debug("entered method doAudit"); - signedEncryptedBallot = null; - command.getCallback().onSuccess(null); - } - - - public void doCastBallot(CastOutputCommand command) { - logger.debug("entered method doCastBallot"); - ScannedData scannedData = ScannedData.newBuilder() - .setChannel(null) //TODO: fill the details for the channel to be able to send here - .setSignedEncryptedBallot(this.signedEncryptedBallot) - .build(); - - Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); - BoolValue b = response.readEntity(BoolValue.class); - response.close(); - - if (b.getValue()) { - command.getCallback().onSuccess(null); - } - else { - command.getCallback().onFailure(new IOException()); - } - } - - - public void doCancel(CancelOutputCommand command) { - logger.debug("entered method doCancel"); - signedEncryptedBallot = null; - command.getCallback().onSuccess(null); - } - } diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index d3e3625..f65959f 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -1,37 +1,84 @@ package meerkat.voting.output; import com.google.protobuf.BoolValue; -import meerkat.pollingstation.PollingStationScanner; -import meerkat.protobuf.PollingStation.*; -import meerkat.rest.*; +import meerkat.protobuf.PollingStation.ScannedData; +import meerkat.protobuf.Voting.SignedEncryptedBallot; +import meerkat.rest.Constants; +import meerkat.rest.ProtobufMessageBodyReader; +import meerkat.rest.ProtobufMessageBodyWriter; +import meerkat.voting.output.outputcommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import javax.ws.rs.client.*; +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 java.io.IOException; -import static meerkat.pollingstation.PollingStationConstants.*; +import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; /** * Created by hai on 27/06/16. */ -public class NetworkVirtualPrinter implements PollingStationScanner.Producer { +public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { - WebTarget successfulScanPath; - WebTarget errorPath; + private Logger logger; + private SignedEncryptedBallot signedEncryptedBallot; + private final WebTarget successfulPrintTarget; public NetworkVirtualPrinter(String address) { + super(); + + logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); + logger.info("A NetworkVirtualPrinter is constructed"); + Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); - successfulScanPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); - errorPath = client.target(address).path(POLLING_STATION_WEB_SCANNER_ERROR_PATH); + successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); } - @Override - public BoolValue newScan(ScannedData scannedData) { - return null; + + public void doCommitToBallot(CommitOutputCommand command) { + logger.debug("entered method doCommitToBallot"); + signedEncryptedBallot = command.getSignedEncryptedBallot(); + command.getCallback().onSuccess(null); } - @Override - public BoolValue reportScanError(ErrorMsg errorMsg) { - return null; + + public void doAudit(AuditOutputCommand command) { + logger.debug("entered method doAudit"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); } + + + public void doCastBallot(CastOutputCommand command) { + logger.debug("entered method doCastBallot"); + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setSignedEncryptedBallot(this.signedEncryptedBallot) + .build(); + + Response response = successfulPrintTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF)); + BoolValue b = response.readEntity(BoolValue.class); + response.close(); + + if (b.getValue()) { + command.getCallback().onSuccess(null); + } + else { + command.getCallback().onFailure(new IOException()); + } + } + + + public void doCancel(CancelOutputCommand command) { + logger.debug("entered method doCancel"); + signedEncryptedBallot = null; + command.getCallback().onSuccess(null); + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 614dc40..62bebe3 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -1,96 +1,28 @@ package meerkat.voting.output; -import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; import meerkat.protobuf.Crypto.*; import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.callbacks.ControllerCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.LinkedBlockingQueue; - /** * A toy OutputDevice class * outputs everything simply to the System console */ -public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { +public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { private Logger logger; - private LinkedBlockingQueue queue; - private volatile boolean shutDownHasBeenCalled; public SystemConsoleOutputDevice () { + super(); logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); - queue = new LinkedBlockingQueue<>(); - shutDownHasBeenCalled = false; } - /* - * Returns the UTF8 decoding of byte-string data - */ - private static String bytesToString(ByteString data) { - return data.toStringUtf8(); - } - @Override - public void run () { - logger.info("UI starts running"); - while (! wasShutDownCalled()) { - try { - OutputCommand command = queue.take(); - handleSingleCommand(command); - } - catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); - } - } - } - - private boolean wasShutDownCalled () { - return shutDownHasBeenCalled; - } - - @Override - public void callShutDown() { - logger.info("callShutDown command has been called"); - shutDownHasBeenCalled = true; - queue.clear(); - } - - - private void handleSingleCommand(OutputCommand command) { - if (command instanceof CommitOutputCommand) { - doCommitToBallot((CommitOutputCommand)command); - } - else if (command instanceof AuditOutputCommand) { - doAudit((AuditOutputCommand)command); - } - else if (command instanceof CastOutputCommand) { - doCastBallot((CastOutputCommand)command); - } - else if (command instanceof CancelOutputCommand) { - doCancel((CancelOutputCommand)command); - } - else { - String errorMessage = "handleSingleCommand: unknown type of OutputCommand received: " + - command.getClass().getName(); - logger.error(errorMessage); - throw new RuntimeException(errorMessage); - } - } - - - @Override - public void commitToBallot(PlaintextBallot plaintextBallot, - SignedEncryptedBallot signedEncryptedBallot, - FutureCallback callback) { - logger.debug("Output interface call to commit to ballot"); - queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); - } public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); @@ -111,12 +43,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { - logger.debug("an interface call to audit"); - queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); - } - public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); System.out.println("Auditing"); @@ -127,12 +53,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void castBallot(FutureCallback callback) { - logger.debug("an interface call to cast ballot"); - queue.add(new CastOutputCommand((ControllerCallback)callback)); - } - public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); System.out.println("Ballot finalized for casting!"); @@ -140,12 +60,6 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { } - @Override - public void cancelBallot(FutureCallback callback) { - logger.debug("an interface call to cancel the output"); - queue.add(new CancelOutputCommand((ControllerCallback)callback)); - } - public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); System.out.println("Ballot cancelled!"); @@ -165,4 +79,12 @@ public class SystemConsoleOutputDevice implements BallotOutputDevice, Runnable { System.out.println(bytesToString(data)); } + + /* + * Returns the UTF8 decoding of byte-string data + */ + private static String bytesToString(ByteString data) { + return data.toStringUtf8(); + } + } From e298ab1e760b1365f00a57bc01372cb135ab1985 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 28 Jun 2016 11:35:36 +0300 Subject: [PATCH 080/106] removed two unnecessary imports --- .../meerkat/pollingstation/PollingStationWebScannerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index e94c633..6e88baa 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -2,9 +2,7 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ByteString; -import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.PollingStation.*; -import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; import meerkat.rest.*; From 8aada211191be8a650275c602431df10c5261f70 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Tue, 28 Jun 2016 15:08:36 +0300 Subject: [PATCH 081/106] Fixed some errors in the tests. Made Threaded Client parameterized (with respect to waiting times and thread count). --- .../SingleServerBulletinBoardClient.java | 16 ++++++------- .../ThreadedBulletinBoardClient.java | 24 ++++++++++++++----- .../MultiServerReadBatchDataWorker.java | 8 +++---- .../CachedBulletinBoardClientTest.java | 2 +- .../GenericBulletinBoardClientTester.java | 5 ++-- .../LocalBulletinBoardClientTest.java | 2 +- ...verBulletinBoardClientIntegrationTest.java | 2 +- ...dedBulletinBoardClientIntegrationTest.java | 5 ++-- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java index be75dfe..e732059 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/SingleServerBulletinBoardClient.java @@ -45,9 +45,9 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar private long lastServerErrorTime; - private final long failDelayInMilliseconds; + private final long FAIL_DELAY_IN_MILLISECONDS; - private final long subscriptionIntervalInMilliseconds; + private final long SUBSCRIPTION_INTERVAL_IN_MILLISECONDS; /** * Notify the client that a job has failed @@ -82,7 +82,7 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar } try { - Thread.sleep(failDelayInMilliseconds); + Thread.sleep(FAIL_DELAY_IN_MILLISECONDS); } catch (InterruptedException e) { //TODO: log } @@ -108,7 +108,7 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar long timeSinceLastServerError = System.currentTimeMillis() - lastServerErrorTime; - if (timeSinceLastServerError >= failDelayInMilliseconds) { + if (timeSinceLastServerError >= FAIL_DELAY_IN_MILLISECONDS) { // Schedule for immediate processing Futures.addCallback(executorService.submit(worker), callback); @@ -118,7 +118,7 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar // Schedule for processing immediately following delay expiry Futures.addCallback(executorService.schedule( worker, - failDelayInMilliseconds - timeSinceLastServerError, + FAIL_DELAY_IN_MILLISECONDS - timeSinceLastServerError, TimeUnit.MILLISECONDS), callback); @@ -330,7 +330,7 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar RetryCallback> retryCallback = new RetryCallback<>(worker, this); // Schedule the worker to run after the given interval has elapsed - Futures.addCallback(executorService.schedule(worker, subscriptionIntervalInMilliseconds, TimeUnit.MILLISECONDS), retryCallback); + Futures.addCallback(executorService.schedule(worker, SUBSCRIPTION_INTERVAL_IN_MILLISECONDS, TimeUnit.MILLISECONDS), retryCallback); } @@ -352,8 +352,8 @@ public class SingleServerBulletinBoardClient implements SubscriptionBulletinBoar this.executorService = executorService; - this.failDelayInMilliseconds = failDelayInMilliseconds; - this.subscriptionIntervalInMilliseconds = subscriptionIntervalInMilliseconds; + this.FAIL_DELAY_IN_MILLISECONDS = failDelayInMilliseconds; + this.SUBSCRIPTION_INTERVAL_IN_MILLISECONDS = subscriptionIntervalInMilliseconds; // Set server error time to a time sufficiently in the past to make new jobs go through lastServerErrorTime = System.currentTimeMillis() - failDelayInMilliseconds; diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index b549a2e..9dd85b9 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -36,13 +36,27 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple 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 final int SERVER_THREADPOOL_SIZE; + private final long FAIL_DELAY; + private final long SUBSCRIPTION_INTERVAL; + + private static final int DEFAULT_SERVER_THREADPOOL_SIZE = 5; + private static final long DEFAULT_FAIL_DELAY = 5000; + private static final long DEFAULT_SUBSCRIPTION_INTERVAL = 10000; private int minAbsoluteRedundancy; + public ThreadedBulletinBoardClient(int serverThreadpoolSize, long failDelay, long subscriptionInterval) { + SERVER_THREADPOOL_SIZE = serverThreadpoolSize; + FAIL_DELAY = failDelay; + SUBSCRIPTION_INTERVAL = subscriptionInterval; + } + + public ThreadedBulletinBoardClient() { + this(DEFAULT_SERVER_THREADPOOL_SIZE, DEFAULT_FAIL_DELAY, DEFAULT_SUBSCRIPTION_INTERVAL); + } + /** * Stores database locations and initializes the web Client * Stores the required minimum redundancy. @@ -232,11 +246,9 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple throw new IllegalArgumentException("Message is not a stub and does not contain the required message ID"); } - MessageID msgID = MessageID.newBuilder().setID(stub.getMsg().getMsgId()).build(); - // Create job MultiServerReadBatchDataWorker worker = - new MultiServerReadBatchDataWorker(clients, minAbsoluteRedundancy, msgID, READ_MESSAGES_RETRY_NUM, callback); + new MultiServerReadBatchDataWorker(clients, minAbsoluteRedundancy, stub, READ_MESSAGES_RETRY_NUM, callback); // Submit job executorService.submit(worker); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java index ab5fd40..769702a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/workers/multiserver/MultiServerReadBatchDataWorker.java @@ -10,10 +10,10 @@ import java.util.List; /** * Created by Arbel Deutsch Peled on 27-Dec-15. */ -public class MultiServerReadBatchDataWorker extends MultiServerGenericReadWorker { +public class MultiServerReadBatchDataWorker extends MultiServerGenericReadWorker { public MultiServerReadBatchDataWorker(List clients, - int minServers, MessageID payload, int maxRetry, + int minServers, BulletinBoardMessage payload, int maxRetry, FutureCallback futureCallback) { super(clients, minServers, payload, maxRetry, futureCallback); @@ -21,8 +21,8 @@ public class MultiServerReadBatchDataWorker extends MultiServerGenericReadWorker } @Override - protected void doRead(MessageID payload, SingleServerBulletinBoardClient client) { - client.readMessage(payload, this); + protected void doRead(BulletinBoardMessage payload, SingleServerBulletinBoardClient client) { + client.readBatchData(payload, this); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java index 83e62ff..8bae8c2 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/CachedBulletinBoardClientTest.java @@ -51,7 +51,7 @@ public class CachedBulletinBoardClientTest { cachedClient = new CachedBulletinBoardClient(localClient, remoteClient, subscriber, queueClient, SYNC_DELAY, SYNC_DELAY); subscriptionTester = new GenericSubscriptionClientTester(cachedClient); - clientTest = new GenericBulletinBoardClientTester(cachedClient); + clientTest = new GenericBulletinBoardClientTester(cachedClient, 87351); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java index f7a4653..7ded2e4 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/GenericBulletinBoardClientTester.java @@ -48,7 +48,6 @@ public class GenericBulletinBoardClientTester { private AsyncBulletinBoardClient bulletinBoardClient; private PostCallback postCallback; - private PostCallback failPostCallback = new PostCallback(true,false); private RedundancyCallback redundancyCallback; private ReadCallback readCallback; @@ -64,7 +63,7 @@ public class GenericBulletinBoardClientTester { // Constructor - public GenericBulletinBoardClientTester(AsyncBulletinBoardClient bulletinBoardClient){ + public GenericBulletinBoardClientTester(AsyncBulletinBoardClient bulletinBoardClient, int seed){ this.bulletinBoardClient = bulletinBoardClient; @@ -113,7 +112,7 @@ public class GenericBulletinBoardClientTester { fail("Couldn't find signing key " + e.getMessage()); } - this.random = new Random(0); + this.random = new Random(seed); this.generator = new BulletinBoardMessageGenerator(random); this.digest = new GenericBulletinBoardDigest(new SHA256Digest()); diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java index 9ee1d60..d33d5ba 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/LocalBulletinBoardClientTest.java @@ -31,7 +31,7 @@ public class LocalBulletinBoardClientTest { LocalBulletinBoardClient client = new LocalBulletinBoardClient(server, THREAD_NUM, SUBSRCIPTION_DELAY); subscriptionTester = new GenericSubscriptionClientTester(client); - clientTest = new GenericBulletinBoardClientTester(client); + clientTest = new GenericBulletinBoardClientTester(client, 98354); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java index 424c4c5..7c8d58b 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/SingleServerBulletinBoardClientIntegrationTest.java @@ -44,7 +44,7 @@ public class SingleServerBulletinBoardClientIntegrationTest { .setMinRedundancy((float) 1.0) .build()); - clientTest = new GenericBulletinBoardClientTester(client); + clientTest = new GenericBulletinBoardClientTester(client, 981541); subscriptionTester = new GenericSubscriptionClientTester(client); } diff --git a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java index dd47354..1187245 100644 --- a/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/meerkat/bulletinboard/ThreadedBulletinBoardClientIntegrationTest.java @@ -28,7 +28,7 @@ public class ThreadedBulletinBoardClientIntegrationTest { public ThreadedBulletinBoardClientIntegrationTest(){ - ThreadedBulletinBoardClient client = new ThreadedBulletinBoardClient(); + ThreadedBulletinBoardClient client = new ThreadedBulletinBoardClient(3,0,500); List testDB = new LinkedList<>(); testDB.add(BASE_URL); @@ -38,7 +38,7 @@ public class ThreadedBulletinBoardClientIntegrationTest { .setMinRedundancy((float) 1.0) .build()); - clientTest = new GenericBulletinBoardClientTester(client); + clientTest = new GenericBulletinBoardClientTester(client, 52351); } @@ -76,6 +76,7 @@ public class ThreadedBulletinBoardClientIntegrationTest { public void testBatchPost() throws CommunicationException, SignatureException, InterruptedException { clientTest.testBatchPost(); + } @Test From 48bf8dbe6b25c86bc31cb04e5267b9db9524f6a3 Mon Sep 17 00:00:00 2001 From: "arbel.peled" Date: Tue, 28 Jun 2016 15:10:38 +0300 Subject: [PATCH 082/106] Ignore .arcconfig --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a14486c..3a97743 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ out *.classpath *.db *.sql +.arcconfig From 66e5db9f227bb32062ad3ed11d889b5454648f18 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:51:49 +0300 Subject: [PATCH 083/106] cleared some unnecessary imports --- .../meerkat/voting/controller/VotingBoothController.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java index e8eae93..6008d24 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothController.java @@ -1,20 +1,17 @@ package meerkat.voting.controller; -import meerkat.protobuf.Voting.*; -import meerkat.voting.controller.selector.QuestionSelector; import meerkat.voting.encryptor.VBCryptoManager; import meerkat.voting.ui.VotingBoothUI; import meerkat.voting.output.BallotOutputDevice; import meerkat.voting.storage.StorageManager; import java.io.IOException; -import java.util.List; /** * An interface for the controller component of the voting booth */ -public interface VotingBoothController extends Runnable{ +public interface VotingBoothController extends Runnable { /** * initialize by setting all the different components of the Voting Booth to be recognized by this controller From 7db62187353bff79fc7e5658c8602138772673ad Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:53:28 +0300 Subject: [PATCH 084/106] fixed: access to the static system messages from the StorageManage class, rather than its instance --- .../voting/controller/VotingBoothImpl.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 849651f..a71dadd 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -1,6 +1,5 @@ package meerkat.voting.controller; -import meerkat.protobuf.Crypto; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; import meerkat.voting.controller.commands.*; @@ -153,7 +152,7 @@ public class VotingBoothImpl implements VotingBoothController { } else { logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); - doReportErrorAndForceRestart(systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE)); + doReportErrorAndForceRestart(systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -182,7 +181,7 @@ public class VotingBoothImpl implements VotingBoothController { queue.clear(); state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); ui.showErrorMessageWithButtons(errorMessage, - new UIElement[]{systemMessages.get(storageManager.RESTART_VOTING_BUTTON)}, + new UIElement[]{systemMessages.get(StorageManager.RESTART_VOTING_BUTTON)}, new ErrorMessageRestartCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); @@ -196,7 +195,7 @@ public class VotingBoothImpl implements VotingBoothController { new ChannelChoiceCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); + systemMessages.get(StorageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE))); } else { logger.debug("doChooseChannel: current state is " + state.stateIdentifier); @@ -215,7 +214,7 @@ public class VotingBoothImpl implements VotingBoothController { new VotingCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNSUCCESSFUL_VOTING_MESSAGE))); + systemMessages.get(StorageManager.UNSUCCESSFUL_VOTING_MESSAGE))); } else { logger.debug("doSetChannelAndAskQuestions: current state is " + state.stateIdentifier); @@ -231,7 +230,7 @@ public class VotingBoothImpl implements VotingBoothController { ui.castOrAudit(new CastOrAuditCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); + systemMessages.get(StorageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE))); } else { logger.debug("doChooseFinalizeOption: current state is " + state.stateIdentifier); @@ -243,25 +242,25 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("doing commit"); try { setBallotData(task); - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_COMMIT_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_COMMIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.commitToBallot(state.plaintextBallot, state.signedEncryptedBallot, new OutputDeviceCommitCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); state.stateIdentifier = VBState.COMMITTING_TO_BALLOT; } catch (SignatureException | IOException e) { logger.error("doCommit: encryption failed. exception: " + e); - UIElement errorMessage = systemMessages.get(storageManager.ENCRYPTION_FAILED_MESSAGE); + UIElement errorMessage = systemMessages.get(StorageManager.ENCRYPTION_FAILED_MESSAGE); UIElement[] buttons = new UIElement[]{ - systemMessages.get(storageManager.RETRY_BUTTON), - systemMessages.get(storageManager.CANCEL_VOTE_BUTTON)}; + systemMessages.get(StorageManager.RETRY_BUTTON), + systemMessages.get(StorageManager.CANCEL_VOTE_BUTTON)}; EncryptionFailedCallback callback = new EncryptionFailedCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -294,28 +293,28 @@ public class VotingBoothImpl implements VotingBoothController { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_AUDIT_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_AUDIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.audit(state.secrets, new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { - ui.notifyVoterToWaitForFinish(systemMessages.get(storageManager.WAIT_FOR_CAST_MESSAGE), + ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.SOMETHING_WRONG_MESSAGE))); + systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE))); outputDevice.castBallot( new OutputDeviceFinalizeCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue, - systemMessages.get(storageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); + systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } } else { From 2b56928e9ace0f93dc4167d1adb15542656db6c3 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 11:54:36 +0300 Subject: [PATCH 085/106] added some JavaDoc comments and documentation --- .../SimpleListCategoriesSelector.java | 10 +++-- .../voting/encryptor/VBCryptoManager.java | 1 + .../voting/encryptor/VBCryptoManagerImpl.java | 4 +- .../output/AsyncRunnableOutputDevice.java | 42 ++++++++++++++----- .../voting/output/BallotOutputDevice.java | 5 ++- .../voting/output/NetworkVirtualPrinter.java | 23 +++++++--- .../output/SystemConsoleOutputDevice.java | 27 ++++++++---- .../outputcommands/AuditOutputCommand.java | 2 +- .../outputcommands/CancelOutputCommand.java | 2 +- .../outputcommands/CastOutputCommand.java | 2 +- .../outputcommands/CommitOutputCommand.java | 2 +- .../output/outputcommands/OutputCommand.java | 4 +- 12 files changed, 90 insertions(+), 34 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index 7f2af87..b39fede 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -69,7 +69,7 @@ public class SimpleListCategoriesSelector implements QuestionSelector { assertDataValid(); } - /* + /** * asserts that the selection data does not contain a question index which is beyond the length of * the ballot race questions array. Otherwise, throws an IndexOutOfBoundsException */ @@ -130,9 +130,11 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return isSelected; } - /* + /** * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). * Otherwise, throws an exception. + * @param ballotAnswer + * @param questionNumber the number of the question (needed only for error message strings) */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { if (ballotAnswer.getAnswerCount() != 1) { @@ -157,8 +159,10 @@ public class SimpleListCategoriesSelector implements QuestionSelector { return selectedQuestions; } - /* + /** * copies a List of Integers into an int[] array of same length + * @param l a list of Integers + * @return an array of ints */ private int[] listToIntArray(List l) { int[] res = new int[l.size()]; diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java index d5216e4..04416f3 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManager.java @@ -7,6 +7,7 @@ import java.security.SignatureException; /** * An interface for the encryptor component of the voting booth + * It handles both the encryption and the digital signature */ public interface VBCryptoManager { /** diff --git a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java index 2bc9729..83fb8b0 100644 --- a/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/encryptor/VBCryptoManagerImpl.java @@ -11,13 +11,13 @@ import java.security.SignatureException; import java.util.Random; /** - * Created by hai on 07/06/16. + * A basic implementation of the VBCryptoManager interface */ public class VBCryptoManagerImpl implements VBCryptoManager { protected final static Logger logger = LoggerFactory.getLogger(VBCryptoManagerImpl.class); - private final Random random; + private final Random random; //TODO: Random object should be more cryptographycally secure private final Encryption encryption; private final DigitalSignature digitalSignature; diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index d4620bb..88dde5b 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -12,7 +12,9 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 27/06/16. + * This is a base class for simple OutputDevices which run asynchronously (as a separate thread). + * The methods of the BallotOutputDevice simply register a matching OutputCommand in the instance's queue + * The Runnable.run method simply takes the next registered command and calls the matching (abstract) method */ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { @@ -52,16 +54,10 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R queue.clear(); } - - abstract void doCommitToBallot(CommitOutputCommand command); - - abstract void doAudit(AuditOutputCommand command); - - abstract void doCastBallot(CastOutputCommand command); - - abstract void doCancel(CancelOutputCommand command); - - + /** + * chooses the next method to run according to the type of the given OutputCommand + * @param command any valid OutputCommand + */ private void handleSingleCommand(OutputCommand command) { if (command instanceof CommitOutputCommand) { doCommitToBallot((CommitOutputCommand)command); @@ -111,4 +107,28 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R } + /** + * This method should be filled by an extending class. It should have the details of how to commit to a ballot + * @param command + */ + abstract void doCommitToBallot(CommitOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to audit the ballot + * @param command + */ + abstract void doAudit(AuditOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to cast the ballot + * @param command + */ + abstract void doCastBallot(CastOutputCommand command); + + /** + * This method should be filled by an extending class. It should have the details of how to cancel the ballot output + * @param command + */ + abstract void doCancel(CancelOutputCommand command); + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java index 97fa7ed..3909ce3 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/BallotOutputDevice.java @@ -20,7 +20,7 @@ public interface BallotOutputDevice { /** * Voter chose 'audit'. Output the ballot secrets to prove correctness of the encryption. - * @param ballotSecrets - the secrtes of the encryption + * @param ballotSecrets - the secrets of the encryption * @param callback - a callback object which expects no return value */ public void audit(BallotSecrets ballotSecrets, FutureCallback callback); @@ -37,5 +37,8 @@ public interface BallotOutputDevice { */ public void cancelBallot(FutureCallback callback); + /** + * A method for shutting down the Output Device + */ public void callShutDown(); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index f65959f..05be623 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -20,20 +20,17 @@ import java.io.IOException; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; /** - * Created by hai on 27/06/16. + * A ballot output device for the network. It simply sends details over the wire */ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); private SignedEncryptedBallot signedEncryptedBallot; private final WebTarget successfulPrintTarget; public NetworkVirtualPrinter(String address) { super(); - - logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); logger.info("A NetworkVirtualPrinter is constructed"); - Client client = ClientBuilder.newClient(); client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); @@ -41,6 +38,12 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for committing. + * It simply keeps the ballot details for later. + * When the voter chooses to Cast the ballot, these details are sent over the wire. + * @param command a CommitOutputCommand with the signed encryption of the ballot + */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); signedEncryptedBallot = command.getSignedEncryptedBallot(); @@ -48,6 +51,9 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for auditing. + */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); signedEncryptedBallot = null; @@ -55,6 +61,10 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * This is where the magic happens. The signed encrypted ballot is transmitted over the wire + * @param command + */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); ScannedData scannedData = ScannedData.newBuilder() @@ -75,6 +85,9 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { } + /** + * The NetworkVirtualPrinter actually does nothing for canceling. + */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); signedEncryptedBallot = null; diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index 62bebe3..c07d8df 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -13,17 +13,18 @@ import org.slf4j.LoggerFactory; */ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class);; public SystemConsoleOutputDevice () { super(); - logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); logger.info("A SystemConsoleOutputDevice is constructed"); } - - - + /** + * Committing to the ballot. + * Simply prints to the output stream all the details in the CommitOutputCommand. + * @param command details to commit to, and the callback to call when finished + */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); PlaintextBallot plaintextBallot = command.getPlaintext(); @@ -43,16 +44,24 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { } + /** + * auditing the ballot. + * prints to the output stream the ballot secrets (the encryption randomness and its proof of random generation) + * @param command An auditing command with the callback to finally call + */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); System.out.println("Auditing"); BallotSecrets ballotSecrets = command.getBallotSecrets(); - printEncryptionRandomness (ballotSecrets.getEncryptionRandomness()); + printEncryptionRandomness(ballotSecrets.getEncryptionRandomness()); printRandomnessGenerationProof (ballotSecrets.getProof()); command.getCallback().onSuccess(null); } - + /** + * Casting the ballot (actually does nothing new) + * @param command + */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); System.out.println("Ballot finalized for casting!"); @@ -60,6 +69,10 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { } + /** + * Canceling the ballot (actually does nothing new) + * @param command + */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); System.out.println("Ballot cancelled!"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java index 2722326..564fb06 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand supplies the necessary details for outputting Audit information */ public class AuditOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java index 0c360d2..26a0388 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -3,7 +3,7 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand signals the output-device that it should Cancel the rest of the ballot output */ public class CancelOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java index af7ed30..a89eb1b 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -3,7 +3,7 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand signals the output-device that the voter wishes to Cast the ballot */ public class CastOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index dcd52f6..a3bd9ac 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; /** - * Created by hai on 15/06/16. + * This OutputCommand supplies the necessary details for outputting a commit to the ballot */ public class CommitOutputCommand extends OutputCommand { diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 8a7c322..7085380 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,7 +2,9 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; -//TODO: make this class generic +/** + * Base class for the commands to put in the output-device queue + */ public abstract class OutputCommand { protected final ControllerCallback callback; From 218677fd96d2c7ae93baf223bd40b56aed656106 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 14:17:11 +0300 Subject: [PATCH 086/106] added many comments and JavaDocs --- .../output/outputcommands/OutputCommand.java | 2 + .../voting/storage/StorageManager.java | 2 +- .../voting/storage/StorageManagerMockup.java | 10 +- .../meerkat/voting/ui/SystemConsoleUI.java | 126 ++++++++++++++++-- .../meerkat/voting/ui/TickerTimerTask.java | 2 +- .../java/meerkat/voting/ui/VotingBoothUI.java | 5 +- .../ui/uicommands/CastOrAuditUICommand.java | 2 +- .../ui/uicommands/ChannelChoiceUICommand.java | 2 +- .../ui/uicommands/FatalErrorUICommand.java | 2 +- .../ui/uicommands/RaceVotingUICommand.java | 2 +- .../ui/uicommands/StartSessionUICommand.java | 2 +- .../voting/ui/uicommands/TickCommand.java | 3 +- .../voting/ui/uicommands/UICommand.java | 4 + .../ui/uicommands/WaitForFinishUICommand.java | 3 +- 14 files changed, 142 insertions(+), 25 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 7085380..342c314 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,6 +2,8 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; +//TODO: make this class generic + /** * Base class for the commands to put in the output-device queue */ diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java index b9ccca7..4a70f79 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManager.java @@ -33,7 +33,7 @@ public interface StorageManager { public Map readSystemMessages() throws IOException; - + // These are just static key identifiers for accessing the matching System Messages in the message map public final static String WAIT_FOR_COMMIT_MESSAGE = "waitForCommit"; public final static String WAIT_FOR_AUDIT_MESSAGE = "waitForAudit"; public final static String WAIT_FOR_CAST_MESSAGE = "waitForCast"; diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java index ea9ac08..f556e3b 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -1,6 +1,5 @@ package meerkat.voting.storage; -import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,7 +7,6 @@ import org.slf4j.LoggerFactory; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashMap; import java.util.Map; /** @@ -17,13 +15,15 @@ import java.util.Map; */ public class StorageManagerMockup implements StorageManager { - private boolean adminHardwareKeyInserted; - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(StorageManagerMockup.class); + public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; + private boolean adminHardwareKeyInserted; + + public StorageManagerMockup () { - logger = LoggerFactory.getLogger(StorageManagerMockup.class); logger.info("A StorageManagerMockup is constructed"); this.adminHardwareKeyInserted = false; } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index b8a3828..c4f0e83 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -18,20 +18,24 @@ import org.slf4j.LoggerFactory; import static java.lang.System.in; +/** + * an asynchronous thread implementation of the VotingBoothUI interface + * This is a mock-up implementation using just the console as our UI device + */ public class SystemConsoleUI implements VotingBoothUI, Runnable { + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleUI.class); + private BufferedReader bufferedReader; private LinkedBlockingQueue queue; - private final Logger logger; - private final int tickDurationInMillisec = 10; private Date startWaitingTime; private volatile boolean shutDownHasBeenCalled; - public SystemConsoleUI() { - logger = LoggerFactory.getLogger(SystemConsoleUI.class); + final int tickDurationInMillisec = 10; // period between view update calls + logger.info("A VB UI console is constructed"); queue = new LinkedBlockingQueue<>(); bufferedReader = new BufferedReader(new InputStreamReader(in)); @@ -44,6 +48,9 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * the run() method. Simply loops and takes commands from the UI's queue and handles them accordingly + */ @Override public void run () { logger.info("UI starts running"); @@ -66,6 +73,13 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.clear(); } + /** + * chooses the next method to run according to the type of the given UICommand. + * Special case for the TickCommand. + * As this command is registered in the queue constantly, we simply ignore this command if the UI is not in + * a waiting state + * @param command any valid UICommand + */ private void handleSingleCommand(UICommand command) { if (!(command instanceof TickCommand)) { if (startWaitingTime != null) { @@ -103,12 +117,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * start a new session by registering a StartSessionUICommand + * @param callback - a boolean future callback to return when done + */ @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); queue.add(new StartSessionUICommand((ControllerCallback)callback)); } + /** + * welcomes the new voter at the beginning of the session + * @param command a StartSessionUICommand with a acallback + */ private void doShowWelcomeScreen(StartSessionUICommand command) { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); @@ -118,11 +140,19 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { callback.onSuccess(null); } + /** + * marks that the waiting, for something else to have happened, is finished + */ private void stopWaiting () { System.out.println (); startWaitingTime = null; } + + /** + * waits until the ENTER key is pressed in the console + * @param message a message to show the user in the console + */ private void waitForEnter(String message) { if (message != null) { System.out.println(message); @@ -141,6 +171,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the channel choice phase by registering a ChannelChoiceUICommand in the queue + * @param questions questions to determine the right voting channel for this voter + * @param callback that's where we store the answers to decide channel upon for the current voter + */ @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); @@ -148,6 +183,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(command); } + /** + * lists the channel choice questions to the voter and gathers the voter's answers + * @param command a ChannelChoiceUICommand with the data and a callback + */ private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) { logger.debug("UI: doAskChannelChoiceQuestions"); System.out.println("Showing questions for choosing channel:\n"); @@ -166,12 +205,21 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the race voting question phase by registering a RaceVotingUICommand in the queue + * @param questions all ballot questions to present to the voter + * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session + */ @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); } + /** + * lists the race voting questions to the voter and gathers the voter's answers + * @param command a RaceVotingUICommand with a callback + */ private void doAskVotingQuestions (RaceVotingUICommand command) { logger.debug("UI: doAskVotingQuestions"); System.out.println("Showing questions for race voting:\n"); @@ -190,12 +238,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * call for the cast-or-audit phase by registering a CastOrAuditUICommand in the queue + * @param callback the returned choice of how to finalize the ballot + */ @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); } + /** + * asks the voter whether to cast or audit the ballot + * @param command a simple CastOrAuditUICommand with the callback + */ private void doCastOrAudit(CastOrAuditUICommand command) { logger.debug("UI entered doCastOrAudit"); System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); @@ -225,12 +281,21 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * makes the UI (and voter) wait for something else to happen, by registering a WaitForFinishUICommand in the queue + * @param message a message to show the user on the UI device while waiting + * @param callback a success return value of the wait (cancelling returns false) + */ @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); } + /** + * Tells the voter (in the console) to wait until some other process is finished + * @param command a simple WaitForFinishUICommand with the callback + */ public void doWaitForFinish (WaitForFinishUICommand command) { logger.debug("UI entered doWaitForFinish"); @@ -247,13 +312,23 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { System.out.print ("Waiting : ."); } + /** + * show an error to the voter. Halts the system until a technician handles it + * @param errorMessage message to show in UI device + * @param callback returns interrupt + */ @Override public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageAndHalt"); throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it."); } - + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param errorMessage message to show in UI device + * @param buttonLabels labels for buttons to present to voter + * @param callback the number of the selected button + */ @Override public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); @@ -261,6 +336,10 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param command a FatalErrorUICommand with the callback + */ private void doFatalError (FatalErrorUICommand command) { logger.debug("UI entered doFatalError"); @@ -301,12 +380,20 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * this method is run when a TickCommand was received while in waiting state + */ private void doTick () { if (startWaitingTime != null) { System.out.print ("."); // still waiting } } + /** + * get an input line from the console + * @return a line from the voter + * @throws IOException + */ private String readInputLine() throws IOException{ String s; try { @@ -323,6 +410,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } + /** + * asserts that the question data matches the types that we can handle in the ConsoleUI + * (better and more sophisticated UI will be able to handle more types of data) + * @param questions list of the questions + */ private void assertQuestionsAreValid (List questions) { for (int index = 0; index < questions.size(); ++index) { BallotQuestion question = questions.get(index); @@ -339,6 +431,15 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + + /** + * present the questions to the voter console sequentially. + * Voter may choose at any time to skip a question, go back or even cancel the whole session + * @param questions list of questions to present + * @return list of answers to the questions (at the same order) + * @throws VoterCancelThrowable this is thrown if a voter chose to cancel in the middle of the process + * @throws IOException + */ private List askVoterForAnswers(List questions) throws VoterCancelThrowable, IOException { assertQuestionsAreValid (questions); @@ -348,7 +449,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { while (index < questions.size()) { BallotQuestion question = questions.get(index); System.out.println("Question number " + index); - showQuestionOnScreen(question); + showQuestionInConsole(question); System.out.println("UI screen: Enter your answer. You can also type '(b)ack' or '(c)ancel' or '(s)kip"); String s = readInputLine(); @@ -372,8 +473,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return answers; } - //show question on the screen for the voter - private void showQuestionOnScreen(BallotQuestion question) { + /** + * present a question in the console to the voter + * @param question a text ballot question + */ + private void showQuestionInConsole(BallotQuestion question) { if (!isQuestionOnlyText(question)) { System.err.println("debug: an element in question is not of TEXT type"); throw new UnsupportedOperationException(); @@ -388,6 +492,11 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { } } + /** + * checks whether the data of the question is only text. This is the only type we can handle in ConsoleUI + * @param question a ballot question to check + * @return True if the question data is only text + */ private boolean isQuestionOnlyText (BallotQuestion question) { boolean isText = true; if (question.getQuestion().getType() != UIElementDataType.TEXT @@ -424,5 +533,4 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { return shutDownHasBeenCalled; } - } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java index a293e5f..594fb6e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -7,7 +7,7 @@ import java.util.TimerTask; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 25/04/16. + * A thread that sends the UI clock TickCommands in a given constant frequency */ class TickerTimerTask extends TimerTask { private LinkedBlockingQueue uiQueue; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java index fccb28e..c4e1f1e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/VotingBoothUI.java @@ -7,10 +7,13 @@ import java.util.List; /** - * An interface for the user interface component of the voting booth + * An interface for the UI component of the voting booth */ public interface VotingBoothUI { + /** + * a simple enum for the voter's finalize choice + */ public enum FinalizeBallotChoice { CAST, AUDIT diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 1b2f72f..6e18b0b 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -3,7 +3,7 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 21/04/16. + * This command signals the UI that the voter should now choose whether to Cast or Audit the ballot */ public class CastOrAuditUICommand extends UICommand { public CastOrAuditUICommand(ControllerCallback callback) { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index 5ad4391..f225ea6 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -6,7 +6,7 @@ import meerkat.voting.controller.callbacks.*; import java.util.List; /** - * Created by hai on 18/04/16. + * This command signals the UI to present channel choice questions to the voter and send back the answers */ public class ChannelChoiceUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java index 7679130..1d47700 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -4,7 +4,7 @@ import meerkat.protobuf.Voting.UIElement; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI that a fatal error occurred and it should notify the voter */ public class FatalErrorUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 6430e59..6b181e6 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -6,7 +6,7 @@ import meerkat.voting.controller.callbacks.*; import java.util.List; /** - * Created by hai on 18/04/16. + * This command signals the UI to present the race voting questions to the voter */ public class RaceVotingUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index 393afa7..d99313e 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -3,7 +3,7 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI to present a new session to a voter */ public class StartSessionUICommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 0872ea3..2e2d033 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -3,7 +3,8 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This is a special UI command which just points out that a tick of the clock occurred + * (so a progress bar can advance while waiting) */ public class TickCommand extends UICommand { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index 460b7d0..4ac47a8 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -3,6 +3,10 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; //TODO: make this class generic + +/** + * Base class for the commands to put in the UI queue + */ public abstract class UICommand { protected final ControllerCallback callback; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index 5c48359..7006014 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -4,9 +4,8 @@ import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.*; /** - * Created by hai on 18/04/16. + * This command signals the UI to wait with an appropriate message until a new command replaces this state */ - public class WaitForFinishUICommand extends UICommand { private final UIElement message; From d8b766725b20b0adf0853a4ddba7a76b30ba1206 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 15:52:05 +0300 Subject: [PATCH 087/106] Removed many compilation warnings by having better handling of Generics types and better JavaDocs --- .../output/AsyncRunnableOutputDevice.java | 18 ++++++++++-------- .../voting/output/NetworkVirtualPrinter.java | 4 +++- .../output/SystemConsoleOutputDevice.java | 6 +++--- .../outputcommands/AuditOutputCommand.java | 4 ++-- .../outputcommands/CancelOutputCommand.java | 4 ++-- .../outputcommands/CastOutputCommand.java | 4 ++-- .../outputcommands/CommitOutputCommand.java | 4 ++-- .../output/outputcommands/OutputCommand.java | 8 +++----- .../ui/uicommands/CastOrAuditUICommand.java | 5 +++-- .../ui/uicommands/ChannelChoiceUICommand.java | 4 ++-- .../ui/uicommands/FatalErrorUICommand.java | 8 ++++---- .../ui/uicommands/RaceVotingUICommand.java | 4 ++-- .../ui/uicommands/StartSessionUICommand.java | 4 ++-- .../voting/ui/uicommands/TickCommand.java | 4 ++-- .../voting/ui/uicommands/UICommand.java | 10 ++++------ .../ui/uicommands/WaitForFinishUICommand.java | 4 ++-- 16 files changed, 48 insertions(+), 47 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 88dde5b..7a856a0 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -5,6 +5,8 @@ import meerkat.protobuf.Voting.BallotSecrets; import meerkat.protobuf.Voting.PlaintextBallot; import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.voting.controller.callbacks.ControllerCallback; +import meerkat.voting.controller.callbacks.OutputDeviceCommitCallback; +import meerkat.voting.controller.callbacks.OutputDeviceFinalizeCallback; import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,49 +87,49 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("Output interface call to commit to ballot"); - queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (ControllerCallback)callback)); + queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (OutputDeviceCommitCallback)callback)); } @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { logger.debug("an interface call to audit"); - queue.add(new AuditOutputCommand(ballotSecrets, (ControllerCallback)callback)); + queue.add(new AuditOutputCommand(ballotSecrets, (OutputDeviceFinalizeCallback)callback)); } @Override public void castBallot(FutureCallback callback) { logger.debug("an interface call to cast ballot"); - queue.add(new CastOutputCommand((ControllerCallback)callback)); + queue.add(new CastOutputCommand((OutputDeviceFinalizeCallback)callback)); } @Override public void cancelBallot(FutureCallback callback) { logger.debug("an interface call to cancel the output"); - queue.add(new CancelOutputCommand((ControllerCallback)callback)); + queue.add(new CancelOutputCommand((ControllerCallback)callback)); } /** * This method should be filled by an extending class. It should have the details of how to commit to a ballot - * @param command + * @param command a CommitOutputCommand with the details and the callback */ abstract void doCommitToBallot(CommitOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to audit the ballot - * @param command + * @param command a AuditOutputCommand with the details and the callback */ abstract void doAudit(AuditOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to cast the ballot - * @param command + * @param command a CastOutputCommand with the details and the callback */ abstract void doCastBallot(CastOutputCommand command); /** * This method should be filled by an extending class. It should have the details of how to cancel the ballot output - * @param command + * @param command a CancelOutputCommand with the details and the callback */ abstract void doCancel(CancelOutputCommand command); diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index 05be623..6ec2583 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -53,6 +53,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * The NetworkVirtualPrinter actually does nothing for auditing. + * @param command a AuditOutputCommand with the details and the callback */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); @@ -63,7 +64,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * This is where the magic happens. The signed encrypted ballot is transmitted over the wire - * @param command + * @param command a CastOutputCommand with the details and the callback */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); @@ -87,6 +88,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { /** * The NetworkVirtualPrinter actually does nothing for canceling. + * @param command a CancelOutputCommand with the callback */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index c07d8df..daf468e 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory; */ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { - private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class);; + private static final Logger logger = LoggerFactory.getLogger(SystemConsoleOutputDevice.class); public SystemConsoleOutputDevice () { super(); @@ -60,7 +60,7 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { /** * Casting the ballot (actually does nothing new) - * @param command + * @param command a CastOutputCommand with the details and the callback */ public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); @@ -71,7 +71,7 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { /** * Canceling the ballot (actually does nothing new) - * @param command + * @param command a CancelOutputCommand with the details and the callback */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java index 564fb06..0d4d6ea 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/AuditOutputCommand.java @@ -6,11 +6,11 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand supplies the necessary details for outputting Audit information */ -public class AuditOutputCommand extends OutputCommand { +public class AuditOutputCommand extends OutputCommand { private final BallotSecrets ballotSecrets; - public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { + public AuditOutputCommand(BallotSecrets ballotSecrets, ControllerCallback callback) { super(callback); this.ballotSecrets = ballotSecrets; } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java index 26a0388..88fe03f 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CancelOutputCommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand signals the output-device that it should Cancel the rest of the ballot output */ -public class CancelOutputCommand extends OutputCommand { +public class CancelOutputCommand extends OutputCommand { - public CancelOutputCommand(ControllerCallback callback) { + public CancelOutputCommand(ControllerCallback callback) { super(callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java index a89eb1b..5098cd5 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CastOutputCommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand signals the output-device that the voter wishes to Cast the ballot */ -public class CastOutputCommand extends OutputCommand { +public class CastOutputCommand extends OutputCommand { - public CastOutputCommand(ControllerCallback callback) { + public CastOutputCommand(ControllerCallback callback) { super(callback); } diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index a3bd9ac..5bec550 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -6,14 +6,14 @@ import meerkat.voting.controller.callbacks.ControllerCallback; /** * This OutputCommand supplies the necessary details for outputting a commit to the ballot */ -public class CommitOutputCommand extends OutputCommand { +public class CommitOutputCommand extends OutputCommand { private final PlaintextBallot plaintextBallot; private final SignedEncryptedBallot signedEncryptedBallot; public CommitOutputCommand(PlaintextBallot plaintextBallot, SignedEncryptedBallot signedEncryptedBallot, - ControllerCallback callback) { + ControllerCallback callback) { super(callback); this.plaintextBallot = plaintextBallot; this.signedEncryptedBallot = signedEncryptedBallot; diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 342c314..59f5ebc 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -2,19 +2,17 @@ package meerkat.voting.output.outputcommands; import meerkat.voting.controller.callbacks.ControllerCallback; -//TODO: make this class generic - /** * Base class for the commands to put in the output-device queue */ -public abstract class OutputCommand { +public abstract class OutputCommand { protected final ControllerCallback callback; - protected OutputCommand(ControllerCallback callback) { + protected OutputCommand(ControllerCallback callback) { this.callback = callback; } - public ControllerCallback getCallback () { + public ControllerCallback getCallback () { return this.callback; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java index 6e18b0b..583a4a2 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/CastOrAuditUICommand.java @@ -1,12 +1,13 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; +import meerkat.voting.ui.VotingBoothUI.FinalizeBallotChoice; /** * This command signals the UI that the voter should now choose whether to Cast or Audit the ballot */ -public class CastOrAuditUICommand extends UICommand { - public CastOrAuditUICommand(ControllerCallback callback) { +public class CastOrAuditUICommand extends UICommand { + public CastOrAuditUICommand(ControllerCallback callback) { super(callback); } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java index f225ea6..185e255 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/ChannelChoiceUICommand.java @@ -8,11 +8,11 @@ import java.util.List; /** * This command signals the UI to present channel choice questions to the voter and send back the answers */ -public class ChannelChoiceUICommand extends UICommand { +public class ChannelChoiceUICommand extends UICommand> { private final List questions; - public ChannelChoiceUICommand(List questions, ControllerCallback callback) + public ChannelChoiceUICommand(List questions, ControllerCallback> callback) { super(callback); this.questions = questions; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java index 1d47700..98af0e4 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/FatalErrorUICommand.java @@ -6,12 +6,12 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI that a fatal error occurred and it should notify the voter */ -public class FatalErrorUICommand extends UICommand { +public class FatalErrorUICommand extends UICommand { private final UIElement errorMessage; private final UIElement[] buttonLabels; - public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) + public FatalErrorUICommand(UIElement errorMessage, UIElement[] buttonLabels, ControllerCallback callback) { super(callback); this.errorMessage = errorMessage; @@ -19,10 +19,10 @@ public class FatalErrorUICommand extends UICommand { } public UIElement getErrorMessage() { - return this.errorMessage; + return errorMessage; } public UIElement[] getButtonLabels() { - return this.getButtonLabels(); + return buttonLabels; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java index 6b181e6..9b329bc 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/RaceVotingUICommand.java @@ -8,11 +8,11 @@ import java.util.List; /** * This command signals the UI to present the race voting questions to the voter */ -public class RaceVotingUICommand extends UICommand { +public class RaceVotingUICommand extends UICommand> { private final List questions; - public RaceVotingUICommand(List questions, ControllerCallback callback) + public RaceVotingUICommand(List questions, ControllerCallback> callback) { super(callback); this.questions = questions; diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java index d99313e..b40bb5d 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/StartSessionUICommand.java @@ -5,9 +5,9 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI to present a new session to a voter */ -public class StartSessionUICommand extends UICommand { +public class StartSessionUICommand extends UICommand { - public StartSessionUICommand(ControllerCallback callback) { + public StartSessionUICommand(ControllerCallback callback) { super(callback); } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java index 2e2d033..e9bb2b7 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/TickCommand.java @@ -6,9 +6,9 @@ import meerkat.voting.controller.callbacks.*; * This is a special UI command which just points out that a tick of the clock occurred * (so a progress bar can advance while waiting) */ -public class TickCommand extends UICommand { +public class TickCommand extends UICommand { - public TickCommand(ControllerCallback callback) { + public TickCommand(ControllerCallback callback) { super(callback); assert null == callback; } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java index 4ac47a8..e579133 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/UICommand.java @@ -2,19 +2,17 @@ package meerkat.voting.ui.uicommands; import meerkat.voting.controller.callbacks.*; -//TODO: make this class generic - /** * Base class for the commands to put in the UI queue */ -public abstract class UICommand { - protected final ControllerCallback callback; +public abstract class UICommand { + protected final ControllerCallback callback; - protected UICommand(ControllerCallback callback) { + protected UICommand(ControllerCallback callback) { this.callback = callback; } - public ControllerCallback getCallback () { + public ControllerCallback getCallback () { return this.callback; } } diff --git a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java index 7006014..5e5d504 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/uicommands/WaitForFinishUICommand.java @@ -6,11 +6,11 @@ import meerkat.voting.controller.callbacks.*; /** * This command signals the UI to wait with an appropriate message until a new command replaces this state */ -public class WaitForFinishUICommand extends UICommand { +public class WaitForFinishUICommand extends UICommand { private final UIElement message; - public WaitForFinishUICommand(UIElement message, ControllerCallback callback) + public WaitForFinishUICommand(UIElement message, ControllerCallback callback) { super(callback); this.message = message; From 2336d44ffc4bb52a13d6ee68af224252adb81efc Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 16:04:04 +0300 Subject: [PATCH 088/106] reduced more compilation warnings by having better Generics type handling and better JavaDocs --- .../selector/SimpleListCategoriesSelector.java | 2 +- .../java/meerkat/voting/ui/SystemConsoleUI.java | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java index b39fede..6b8f78b 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/selector/SimpleListCategoriesSelector.java @@ -133,7 +133,7 @@ public class SimpleListCategoriesSelector implements QuestionSelector { /** * Verifies that the ballot answer is of length 1. (We do not yet handle multi-choice questions in the channel choice round). * Otherwise, throws an exception. - * @param ballotAnswer + * @param ballotAnswer the answer to verify whose length is one * @param questionNumber the number of the question (needed only for error message strings) */ private void assertAnswerLengthIsOne (BallotAnswer ballotAnswer, int questionNumber) { diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index c4f0e83..e35c527 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -124,7 +124,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); - queue.add(new StartSessionUICommand((ControllerCallback)callback)); + queue.add(new StartSessionUICommand((NewVoterCallback)callback)); } /** @@ -135,8 +135,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { logger.debug("UI entered doShowWelcomeScreen"); System.out.println("Welcome, new voter!"); waitForEnter(null); - ControllerCallback callback = command.getCallback(); - assert (callback instanceof NewVoterCallback); + ControllerCallback callback = command.getCallback(); callback.onSuccess(null); } @@ -179,7 +178,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ControllerCallback)callback); + ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback); queue.add(command); } @@ -213,7 +212,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - queue.add(new RaceVotingUICommand(questions, (ControllerCallback)callback)); + queue.add(new RaceVotingUICommand(questions, (VotingCallback)callback)); } /** @@ -245,7 +244,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); - queue.add(new CastOrAuditUICommand((ControllerCallback)callback)); + queue.add(new CastOrAuditUICommand((CastOrAuditCallback)callback)); } /** @@ -289,7 +288,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishUICommand(message, (ControllerCallback)callback)); + queue.add(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); } /** @@ -333,7 +332,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); queue.clear(); - queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } /** From 853a6b5684df06d01a1ce49d98b1f172c744aa23 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Mon, 4 Jul 2016 16:05:52 +0300 Subject: [PATCH 089/106] Another (final) Generics type fix --- .../meerkat/voting/output/outputcommands/OutputCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java index 59f5ebc..89591fb 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/OutputCommand.java @@ -6,13 +6,13 @@ import meerkat.voting.controller.callbacks.ControllerCallback; * Base class for the commands to put in the output-device queue */ public abstract class OutputCommand { - protected final ControllerCallback callback; + protected final ControllerCallback callback; protected OutputCommand(ControllerCallback callback) { this.callback = callback; } public ControllerCallback getCallback () { - return this.callback; + return callback; } } From b1a033da5e2061bfb7362a03457a60e56252371b Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 6 Jul 2016 13:24:10 +0300 Subject: [PATCH 090/106] Add the channel identifier to the PlaintextBallot, so it is now printed by the output device --- .../src/main/proto/meerkat/voting.proto | 6 ++--- .../voting/output/NetworkVirtualPrinter.java | 23 +++++++++++++------ .../output/SystemConsoleOutputDevice.java | 5 +++- .../outputcommands/CommitOutputCommand.java | 5 ++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index c253a88..0c2963c 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -60,9 +60,9 @@ message BallotAnswer { } message PlaintextBallot { - uint64 serialNumber = 1; // Ballot serial number - - repeated BallotAnswer answers = 2; + uint64 serial_number = 1; // Ballot serial number + bytes channel_identifier = 2; + repeated BallotAnswer answers = 3; } message EncryptedBallot { diff --git a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java index 6ec2583..74f9970 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java +++ b/voting-booth/src/main/java/meerkat/voting/output/NetworkVirtualPrinter.java @@ -1,6 +1,7 @@ package meerkat.voting.output; import com.google.protobuf.BoolValue; +import com.google.protobuf.ByteString; import meerkat.protobuf.PollingStation.ScannedData; import meerkat.protobuf.Voting.SignedEncryptedBallot; import meerkat.rest.Constants; @@ -10,10 +11,7 @@ import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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.client.*; import javax.ws.rs.core.Response; import java.io.IOException; @@ -25,6 +23,7 @@ import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { private static final Logger logger = LoggerFactory.getLogger(NetworkVirtualPrinter.class); + private ByteString channelIdentifier; private SignedEncryptedBallot signedEncryptedBallot; private final WebTarget successfulPrintTarget; @@ -35,6 +34,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { client.register(ProtobufMessageBodyReader.class); client.register(ProtobufMessageBodyWriter.class); successfulPrintTarget = client.target(address).path(POLLING_STATION_WEB_SCANNER_SCAN_PATH); + resetState(); } @@ -46,6 +46,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doCommitToBallot(CommitOutputCommand command) { logger.debug("entered method doCommitToBallot"); + channelIdentifier = command.getChannelIdentifierByteString(); signedEncryptedBallot = command.getSignedEncryptedBallot(); command.getCallback().onSuccess(null); } @@ -57,7 +58,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doAudit(AuditOutputCommand command) { logger.debug("entered method doAudit"); - signedEncryptedBallot = null; + resetState(); command.getCallback().onSuccess(null); } @@ -69,7 +70,7 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { public void doCastBallot(CastOutputCommand command) { logger.debug("entered method doCastBallot"); ScannedData scannedData = ScannedData.newBuilder() - .setChannel(null) //TODO: fill the details for the channel to be able to send here + .setChannel(channelIdentifier) .setSignedEncryptedBallot(this.signedEncryptedBallot) .build(); @@ -77,6 +78,8 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { BoolValue b = response.readEntity(BoolValue.class); response.close(); + resetState(); + if (b.getValue()) { command.getCallback().onSuccess(null); } @@ -92,8 +95,14 @@ public class NetworkVirtualPrinter extends AsyncRunnableOutputDevice { */ public void doCancel(CancelOutputCommand command) { logger.debug("entered method doCancel"); - signedEncryptedBallot = null; + resetState(); command.getCallback().onSuccess(null); } + + private void resetState() { + channelIdentifier = null; + signedEncryptedBallot = null; + } + } diff --git a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java index daf468e..4f50c27 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/SystemConsoleOutputDevice.java @@ -29,7 +29,10 @@ public class SystemConsoleOutputDevice extends AsyncRunnableOutputDevice { logger.debug("entered method doCommitToBallot"); PlaintextBallot plaintextBallot = command.getPlaintext(); long plaintextSerialNumber = plaintextBallot.getSerialNumber(); - System.out.println("Commitment of Ballot #" + plaintextSerialNumber + " (plaintext):"); + System.out.println("Commitment of Ballot #" + plaintextSerialNumber); + System.out.println("(channel): "); + System.out.println(bytesToString(command.getChannelIdentifierByteString())); + System.out.println("(plaintext): "); System.out.println(plaintextBallot); SignedEncryptedBallot signedEncryptedBallot = command.getSignedEncryptedBallot(); long encryptedSerialNumber = signedEncryptedBallot.getEncryptedBallot().getSerialNumber(); diff --git a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java index 5bec550..42c9307 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java +++ b/voting-booth/src/main/java/meerkat/voting/output/outputcommands/CommitOutputCommand.java @@ -1,5 +1,6 @@ package meerkat.voting.output.outputcommands; +import com.google.protobuf.ByteString; import meerkat.protobuf.Voting.*; import meerkat.voting.controller.callbacks.ControllerCallback; @@ -19,6 +20,10 @@ public class CommitOutputCommand extends OutputCommand { this.signedEncryptedBallot = signedEncryptedBallot; } + public ByteString getChannelIdentifierByteString() { + return plaintextBallot.getChannelIdentifier(); + } + public PlaintextBallot getPlaintext() { return plaintextBallot; } From d804f0dbacfb69849831c3763350b5c494b743a8 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 6 Jul 2016 21:33:30 +0300 Subject: [PATCH 091/106] voting-booth gradle.build now has dependencies on jetty and RESTful API for testing purposes --- voting-booth/build.gradle | 8 ++++++++ .../java/meerkat/voting/NetworkVirtualPrinterTest.java | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index ef89f86..88bd338 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -42,6 +42,14 @@ dependencies { compile project(':meerkat-common') compile project(':restful-api-common') + // Jersey for RESTful API + compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.5.+' + + // Servlets + compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.+' + compile 'org.eclipse.jetty:jetty-server:9.3.+' + compile 'org.eclipse.jetty:jetty-servlet:9.3.+' + // Logging compile 'org.slf4j:slf4j-api:1.7.7' runtime 'ch.qos.logback:logback-classic:1.1.2' diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java new file mode 100644 index 0000000..ec5cd4c --- /dev/null +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -0,0 +1,7 @@ +package meerkat.voting; + +/** + * Created by hai on 06/07/16. + */ +public class NetworkVirtualPrinterTest { +} From b667de95aa920793a032ac70a5a2141de39af429 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:49:25 +0300 Subject: [PATCH 092/106] Fix protobuf definition of EncryptedBallot to match the standard convention. --- meerkat-common/src/main/proto/meerkat/voting.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meerkat-common/src/main/proto/meerkat/voting.proto b/meerkat-common/src/main/proto/meerkat/voting.proto index 26ac60c..6e03a5b 100644 --- a/meerkat-common/src/main/proto/meerkat/voting.proto +++ b/meerkat-common/src/main/proto/meerkat/voting.proto @@ -66,7 +66,7 @@ message PlaintextBallot { } message EncryptedBallot { - uint64 serialNumber = 1; // Ballot serial number + uint64 serial_number = 1; // Ballot serial number RerandomizableEncryptedMessage data = 2; } From f2836d277a47df2af1012350e699aaf5e5aa88bb Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:50:21 +0300 Subject: [PATCH 093/106] Add polling-station project dependency to VB build.gradle for testing purposes --- voting-booth/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index 549788d..544f0b4 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -60,6 +60,10 @@ dependencies { testCompile 'junit:junit:4.+' runtime 'org.codehaus.groovy:groovy:2.4.+' + + // Meerkat polling station + compile project(':polling-station') + } From 5404bb9ed2139fb9536505d322d7574109621255 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:51:16 +0300 Subject: [PATCH 094/106] Fix error in setting name of output device thread --- .../src/main/java/meerkat/voting/VotingBoothToyRun.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java index dfd9b6a..65b6685 100644 --- a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyRun.java @@ -58,7 +58,7 @@ public class VotingBoothToyRun { Thread uiThread = new Thread(ui); uiThread.setName("Meerkat VB-UI Thread"); Thread outputThread = new Thread(outputDevice); - uiThread.setName("Meerkat VB-Output Thread"); + outputThread.setName("Meerkat VB-Output Thread"); uiThread.start(); controllerThread.start(); From 42d68b7ce88d9333acb229cc0365711dbbe8bc20 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 11:54:50 +0300 Subject: [PATCH 095/106] Test: Add NetworkVirtualPrinterTest --- .../voting/NetworkVirtualPrinterTest.java | 224 +++++++++++++++++- 1 file changed, 222 insertions(+), 2 deletions(-) diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java index ec5cd4c..827bf93 100644 --- a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -1,7 +1,227 @@ package meerkat.voting; + +import com.google.common.util.concurrent.FutureCallback; + +import meerkat.protobuf.Crypto.*; +import meerkat.protobuf.PollingStation.*; + +import com.google.protobuf.ByteString; +import meerkat.pollingstation.PollingStationScanner; +import meerkat.pollingstation.PollingStationWebScanner; + +import meerkat.protobuf.Voting.*; +import meerkat.voting.controller.callbacks.OutputDeviceCommitCallback; +import meerkat.voting.controller.callbacks.OutputDeviceFinalizeCallback; +import meerkat.voting.output.NetworkVirtualPrinter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.Semaphore; + + +import static org.hamcrest.MatcherAssert.assertThat; + /** - * Created by hai on 06/07/16. + * A test for the NetworkVirtualPrinter + * coded with too much effort by Hai, based on the PollingStationWebScannerTest coded by Arbel */ + + + public class NetworkVirtualPrinterTest { -} + + private PollingStationScanner.Consumer scanner; + private static final String ADDRESS = "http://localhost"; + private static final String SUB_ADDRESS = ""; + private static final int PORT = 8080; + + private Semaphore semaphore1; + private Semaphore semaphore2; + private Throwable thrown; + private boolean dataIsAsExpected; + + private NetworkVirtualPrinter networkPrinter; + + + private class ScanHandler implements FutureCallback { + + private final ScannedData expectedData; + + public ScanHandler(ScannedData expectedData) { + this.expectedData = expectedData; + } + + @Override + public void onSuccess(ScannedData result) { + dataIsAsExpected = result.equals(expectedData); + semaphore2.release(); + } + + @Override + public void onFailure(Throwable t) { + dataIsAsExpected = false; + thrown = t; + semaphore2.release(); + } + } + + private class CommitHandler extends OutputDeviceCommitCallback { + + private boolean success; + + public CommitHandler(int requestId, long serialNumber) { + super(requestId, serialNumber, null, null); + success = false; + } + + @Override + public void onSuccess(Void v) { + System.out.println("CommitHandler success"); + success = true; + } + + @Override + public void onFailure(Throwable t) { + assertThat("Commit to ballot failed " + t.getMessage(), false); + } + + public boolean gotSuccess() { + return success; + } + } + + private class CastHandler extends OutputDeviceFinalizeCallback { + + private boolean success; + + public CastHandler(int requestId, long serialNumber) { + super(requestId, serialNumber, null, null); + success = false; + } + + @Override + public void onSuccess(Void v) { + System.out.println("CastHandler success"); + success = true; + semaphore1.release(); + } + + @Override + public void onFailure(Throwable t) { + semaphore1.release(); + assertThat("Cast ballot failed " + t.getMessage(), false); + } + + public boolean gotSuccess() { + return success; + } + } + + @Before + public void init() { + + System.err.println("Setting up Scanner WebApp!"); + + scanner = new PollingStationWebScanner(PORT, SUB_ADDRESS); + + semaphore1 = new Semaphore(0); + semaphore2 = new Semaphore(0); + thrown = null; + + try { + scanner.start(); + } catch (Exception e) { + assertThat("Could not start server: " + e.getMessage(), false); + } + + networkPrinter = new NetworkVirtualPrinter(ADDRESS + ":" + PORT); + Thread outputThread = new Thread(networkPrinter); + outputThread.setName("Meerkat VB-Output Thread"); + outputThread.start(); + + } + + @Test + public void testSuccessfulScan() throws InterruptedException { + + // create scannedData + + byte[] channel = {(byte) 1, (byte) 2}; + byte[] encMessageData = {(byte) 50, (byte) 51, (byte) 52}; + byte[] signatureData = {(byte) 93, (byte) 95, (byte) 95}; + byte[] signerId = {(byte) 17, (byte) 18, (byte) 19}; + int serialNumber = 17; + + PlaintextBallot plaintextBallot = PlaintextBallot.newBuilder() + .setChannelIdentifier(ByteString.copyFrom(channel)) + .setSerialNumber(serialNumber) + .build(); + + RerandomizableEncryptedMessage encMessage = RerandomizableEncryptedMessage.newBuilder() + .setData(ByteString.copyFrom(encMessageData)) + .build(); + + EncryptedBallot encryptedBallot = EncryptedBallot.newBuilder() + .setSerialNumber(serialNumber) + .setData(encMessage) + .build(); + + Signature signature = Signature.newBuilder() + .setType(SignatureType.ECDSA) + .setData(ByteString.copyFrom(signatureData)) + .setSignerId(ByteString.copyFrom(signerId)) + .build(); + + SignedEncryptedBallot signedEncryptedBallot = SignedEncryptedBallot.newBuilder() + .setEncryptedBallot(encryptedBallot) + .setSignature(signature) + .build(); + + ScannedData scannedData = ScannedData.newBuilder() + .setChannel(ByteString.copyFrom(channel)) + .setSignedEncryptedBallot(signedEncryptedBallot) + .build(); + + + scanner.subscribe(new ScanHandler(scannedData)); + + //Send scan + + CommitHandler commitHandler = new CommitHandler(0, serialNumber); + networkPrinter.commitToBallot(plaintextBallot, signedEncryptedBallot, commitHandler); + CastHandler castHandler = new CastHandler(1, serialNumber); + networkPrinter.castBallot(castHandler); + + + + semaphore1.acquire(); + semaphore2.acquire(); + + // Make sure the response was valid + + assertThat("Commit to ballot callback did not receive success", commitHandler.gotSuccess()); + assertThat("Cast ballot callback did not receive success", castHandler.gotSuccess()); + + assertThat("Scanner has thrown an error", thrown == null); + assertThat("Scanned data received was incorrect", dataIsAsExpected); + + } + + @After + public void close() { + + System.err.println("Scanner WebApp shutting down..."); + + try { + scanner.stop(); + } catch (Exception e) { + assertThat("Could not stop server: " + e.getMessage(), false); + } + + networkPrinter.callShutDown(); + + } + +} \ No newline at end of file From 0956fa98d37fa471ca4134fcb2e9ca85d9ca085d Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 15:23:46 +0300 Subject: [PATCH 096/106] Refactor: add comments to VotingBoothImpl.java, and rename tasks to commands (because they were two names of the same thing) Signed-off-by: Hai Brenner --- .../voting/controller/VotingBoothImpl.java | 159 +++++++++++++----- 1 file changed, 118 insertions(+), 41 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index a71dadd..92c1e5e 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -24,29 +24,30 @@ import java.util.concurrent.LinkedBlockingQueue; */ public class VotingBoothImpl implements VotingBoothController { + private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class);; + + // the component interfaces of the Voting Booth private BallotOutputDevice outputDevice; private VBCryptoManager crypto; private VotingBoothUI ui; private StorageManager storageManager; + + // election details and info private List questionsForChoosingChannel; private List questions; private QuestionSelector questionSelector; private Map systemMessages; - private LinkedBlockingQueue queue; - - private Logger logger; - + // state private ControllerState state; private volatile boolean shutDownHasBeenCalled; - + private LinkedBlockingQueue queue; protected final int MAX_REQUEST_IDENTIFIER = 100000; private static int requestCounter = 0; - + // a simple constructor public VotingBoothImpl () { - logger = LoggerFactory.getLogger(VotingBoothImpl.class); logger.info("A VotingBoothImpl is constructed"); shutDownHasBeenCalled = false; queue = new LinkedBlockingQueue<>(); @@ -59,11 +60,14 @@ public class VotingBoothImpl implements VotingBoothController { VotingBoothUI vbUI, StorageManager vbStorageManager) throws IOException { logger.info("init is called"); + + // keep pointers to the VB components this.outputDevice = outputDevice; this.crypto = vbCrypto; this.ui = vbUI; this.storageManager = vbStorageManager; + // store election details and info ElectionParams electionParams; try { logger.info("init: reading election params"); @@ -92,6 +96,10 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * a method for running the Voting flow of the VB (in contrast to the admin-setup flow + * It simply loops: takes the next command in its inner queue and handles it + */ private void runVotingFlow () { logger.info("entered the voting flow"); @@ -99,11 +107,11 @@ public class VotingBoothImpl implements VotingBoothController { while (! wasShutDownCalled()) { try { - ControllerCommand task = queue.take(); - handleSingleTask (task); + ControllerCommand Command = queue.take(); + handleSingleCommand(Command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from task queue " + e); + logger.warn ("Interrupted while reading from command queue " + e); } } } @@ -117,41 +125,48 @@ public class VotingBoothImpl implements VotingBoothController { outputDevice.callShutDown(); } - private void handleSingleTask (ControllerCommand task) { - if (task.getBallotSerialNumber() != state.currentBallotSerialNumber && !(task instanceof RestartVotingCommand)) { + /** + * this method decides upon a given command if to ignore it (if it has an old serial number) or to handle it + * If we choose to handle it, then it simply calls the matching method which handles this type of command + * @param command a command to handle next (probably from the inner command queue) + */ + private void handleSingleCommand(ControllerCommand command) { + // check if the command is old and should be ignored + if (command.getBallotSerialNumber() != state.currentBallotSerialNumber && !(command instanceof RestartVotingCommand)) { // probably an old command relating to some old ballot serial number. Simply log it and ignore it. - String errorMessage = "handleSingleTask: received a task too old. " + - task.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; + String errorMessage = "handleSingleCommand: received a task too old. " + + command.getBallotSerialNumber() + " " + state.currentBallotSerialNumber; logger.debug(errorMessage); return; } - if (task instanceof RestartVotingCommand) { + // decide which method to run according to the command type + if (command instanceof RestartVotingCommand) { doRestartVoting (); } - else if (task instanceof ChannelChoiceCommand) { + else if (command instanceof ChannelChoiceCommand) { doChooseChannel(); } - else if (task instanceof ChannelDeterminedCommand) { - doSetChannelAndAskQuestions ((ChannelDeterminedCommand)task); + else if (command instanceof ChannelDeterminedCommand) { + doSetChannelAndAskQuestions ((ChannelDeterminedCommand)command); } - else if (task instanceof ChooseFinalizeOptionCommand) { + else if (command instanceof ChooseFinalizeOptionCommand) { doChooseFinalizeOption(); } - else if (task instanceof CastCommand) { + else if (command instanceof CastCommand) { doFinalize(false); } - else if (task instanceof AuditCommand) { + else if (command instanceof AuditCommand) { doFinalize(true); } - else if (task instanceof EncryptAndCommitBallotCommand) { - doCommit ((EncryptAndCommitBallotCommand)task); + else if (command instanceof EncryptAndCommitBallotCommand) { + doCommit ((EncryptAndCommitBallotCommand)command); } - else if (task instanceof ReportErrorCommand) { - doReportErrorAndForceRestart((ReportErrorCommand)task); + else if (command instanceof ReportErrorCommand) { + doReportErrorAndForceRestart((ReportErrorCommand)command); } else { - logger.error("handleSingleTask: unknown type of ControllerCommand received: " + task.getClass().getName()); + logger.error("handleSingleCommand: unknown type of ControllerCommand received: " + command.getClass().getName()); doReportErrorAndForceRestart(systemMessages.get(StorageManager.SOMETHING_WRONG_MESSAGE)); } } @@ -166,17 +181,28 @@ public class VotingBoothImpl implements VotingBoothController { //TODO: add commands to actually shut down the machine } + /** + * a method to execute a Restart Voting Command + */ private void doRestartVoting () { queue.clear(); state.clearAndResetState(VBState.NEW_VOTER); - ui.startNewVoterSession(new NewVoterCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, this.queue)); } - private void doReportErrorAndForceRestart(ReportErrorCommand task) { - doReportErrorAndForceRestart(task.getErrorMessage()); + /** + * a (overloaded) method to execute a Report Error Command. + * It actually just runs the overloaded version of this method with the error message inside the command + * @param command the command has the info of the error message to report + */ + private void doReportErrorAndForceRestart(ReportErrorCommand command) { + doReportErrorAndForceRestart(command.getErrorMessage()); } + /** + * a (overloaded) method to report an error message to the voter + * @param errorMessage message to show the voter + */ private void doReportErrorAndForceRestart(UIElement errorMessage) { queue.clear(); state.clearAndResetState(VBState.FATAL_ERROR_FORCE_NEW_VOTER); @@ -187,6 +213,10 @@ public class VotingBoothImpl implements VotingBoothController { this.queue)); } + /** + * a method to execute a Channel Choice Command + * it notifies the UI to present the channel choice questions to the voter + */ private void doChooseChannel () { if (state.stateIdentifier == VBState.NEW_VOTER) { logger.debug("doing chooseChannel"); @@ -203,11 +233,17 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void doSetChannelAndAskQuestions (ChannelDeterminedCommand task) { + /** + * a method to execute a Channel Determined Command + * (this actually sets the channel now after the voter has answered the channel choice questions) + * It then determines the race questions for the voter, and notifies the UI to present them to the voter + * @param command details of the voter's answers on the channel choice questions + */ + private void doSetChannelAndAskQuestions (ChannelDeterminedCommand command) { if (state.stateIdentifier == VBState.CHOOSE_CHANNEL) { logger.debug("doing set channel and ask questions"); state.stateIdentifier = VBState.ANSWER_QUESTIONS; - List channelChoiceAnswers = task.channelChoiceAnswers; + List channelChoiceAnswers = command.channelChoiceAnswers; state.channelIdentifier = questionSelector.getChannelIdentifier(channelChoiceAnswers); state.channelSpecificQuestions = questionSelector.selectQuestionsForVoter(state.channelIdentifier); ui.askVoterQuestions(state.channelSpecificQuestions, @@ -222,7 +258,10 @@ public class VotingBoothImpl implements VotingBoothController { } } - + /** + * a method to execute a Do-Finalzie-Option Command + * notifies the UI to present the cast-or-audit question to the voter + */ private void doChooseFinalizeOption() { if (state.stateIdentifier == VBState.COMMITTING_TO_BALLOT) { logger.debug("doChooseFinalizeOption"); @@ -237,11 +276,17 @@ public class VotingBoothImpl implements VotingBoothController { // ignore this request } } - private void doCommit (EncryptAndCommitBallotCommand task) { + + /** + * a method to execute a Encrypt-and-Commit Command + * It sends a notification to commit to the output device + * @param command details of the voter's answers on the ballot questions + */ + private void doCommit (EncryptAndCommitBallotCommand command) { if (state.stateIdentifier == VBState.ANSWER_QUESTIONS) { logger.debug("doing commit"); try { - setBallotData(task); + setBallotData(command); ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_COMMIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -257,6 +302,9 @@ public class VotingBoothImpl implements VotingBoothController { } catch (SignatureException | IOException e) { logger.error("doCommit: encryption failed. exception: " + e); + + // in case the encryption failed for some unknown reason, we send the UI a notification + // to ask the voter whether he wants to retry or cancel the ballot UIElement errorMessage = systemMessages.get(StorageManager.ENCRYPTION_FAILED_MESSAGE); UIElement[] buttons = new UIElement[]{ systemMessages.get(StorageManager.RETRY_BUTTON), @@ -274,25 +322,41 @@ public class VotingBoothImpl implements VotingBoothController { } } - private void setBallotData (EncryptAndCommitBallotCommand task) throws IOException, SignatureException{ - if (! (task instanceof RetryEncryptAndCommitBallotCommand)) { + /** + * encrypt the ballot, and keep all info (plaintext, encryption and secrets) in the state's attributes + * @param command either an EncryptAndCommitBallotCommand if we encrypt the plaintext for the first time, or a RetryEncryptAndCommitBallotCommand if we already got here but encryption failed before + * @throws IOException problems in the encryption process + * @throws SignatureException problems in the digital signature process + */ + private void setBallotData (EncryptAndCommitBallotCommand command) throws IOException, SignatureException{ + // a Retry command is given only if we first got here, and later the encryption failed but the voter chose to retry + // in such a case the plaintext is already set from previous attempt + if (! (command instanceof RetryEncryptAndCommitBallotCommand)) { // this is not a retry attempt, so the plaintext is not set yet // otherwise, we have the plaintext from the previous encryption attempt state.plaintextBallot = PlaintextBallot.newBuilder() - .setSerialNumber(task.getBallotSerialNumber()) - .addAllAnswers(task.getVotingAnswers()) + .setSerialNumber(command.getBallotSerialNumber()) + .addAllAnswers(command.getVotingAnswers()) .build(); } + + // keep the encryption and the secrets we used for it EncryptionAndSecrets encryptionAndSecrets = crypto.encrypt(state.plaintextBallot); state.signedEncryptedBallot = encryptionAndSecrets.getSignedEncryptedBallot(); state.secrets = encryptionAndSecrets.getSecrets(); } + /** + * a method to execute a Cast Command or an Audit Command + * according to the flag, chooses which finalize ballot task to send to the output device + * @param auditRequested true if we wish to finalize by auditing. false if we finalize by casting the ballot + */ private void doFinalize (boolean auditRequested) { if (state.stateIdentifier == VBState.CAST_OR_AUDIT) { logger.debug("finalizing"); state.stateIdentifier = VBState.FINALIZING; if (auditRequested) { + // finalize by auditing ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_AUDIT_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -305,6 +369,7 @@ public class VotingBoothImpl implements VotingBoothController { systemMessages.get(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE))); } else { + // finalize by casting the ballot ui.notifyVoterToWaitForFinish(systemMessages.get(StorageManager.WAIT_FOR_CAST_MESSAGE), new WaitForFinishCallback(generateRequestIdentifier(), state.currentBallotSerialNumber, @@ -325,8 +390,7 @@ public class VotingBoothImpl implements VotingBoothController { - - + // an enum to keep the step (of the voting process) in which the VB is currently in private enum VBState { NEW_VOTER, CHOOSE_CHANNEL, @@ -339,6 +403,15 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * a class to keep and directly access all the details of the VB controller state. + * naming: + * - the (enum) state identifier of the current step + * - the chosen channel + * - all details of the ballot (both plaintext and encryption) + * - last request identifier (to one of the other component interfaces) + * - serial number of the current ballot + */ private class ControllerState { public VBState stateIdentifier; public byte[] channelIdentifier; @@ -359,7 +432,6 @@ public class VotingBoothImpl implements VotingBoothController { currentBallotSerialNumber = 0; } - private void clearPlaintext () { plaintextBallot = null; } @@ -379,6 +451,11 @@ public class VotingBoothImpl implements VotingBoothController { } + /** + * Creates a new request identifier to identify any call to one of the other component interfaces. + * We limit its value to MAX_REQUEST_IDENTIFIER, so the identifier is kept short. + * @return a new request identifier + */ private int generateRequestIdentifier() { ++requestCounter; if (requestCounter >= MAX_REQUEST_IDENTIFIER) { From 88991ea9ff89de02ec854557a6194fdaf35e03a5 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 12 Jul 2016 15:32:22 +0300 Subject: [PATCH 097/106] Refactor: some more comments, and better looking code in VotingBoothImpl.java --- .../meerkat/voting/controller/VotingBoothImpl.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java index 92c1e5e..4903424 100644 --- a/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java +++ b/voting-booth/src/main/java/meerkat/voting/controller/VotingBoothImpl.java @@ -20,11 +20,16 @@ import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; /** - * Created by hai on 28/03/16. + * An asynchronous implementation of the VotingBoothController. + * This implementation binds the other components (storage, ui, output device, and crypto manager), + * and runs as its own thread controlling the whole VB process. + * The high level details are that it has a queue of commands to handle in order, and a State object which keeps + * all data from previous tasks which is necessary for the next task. + * It calls executions in the UI and output device asynchronously. */ public class VotingBoothImpl implements VotingBoothController { - private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class);; + private final Logger logger = LoggerFactory.getLogger(VotingBoothImpl.class); // the component interfaces of the Voting Booth private BallotOutputDevice outputDevice; @@ -34,7 +39,6 @@ public class VotingBoothImpl implements VotingBoothController { // election details and info private List questionsForChoosingChannel; - private List questions; private QuestionSelector questionSelector; private Map systemMessages; @@ -82,8 +86,8 @@ public class VotingBoothImpl implements VotingBoothController { logger.info("init: setting the election parameters"); this.questionsForChoosingChannel = electionParams.getChannelChoiceQuestionsList(); - this.questions = electionParams.getRaceQuestionsList(); - this.questionSelector = new SimpleListCategoriesSelector(this.questions, electionParams.getSelectionData()); + List questions = electionParams.getRaceQuestionsList(); + this.questionSelector = new SimpleListCategoriesSelector(questions, electionParams.getSelectionData()); logger.info("init: setting finished"); } From 1cf16d83861c264d73f9afc4e32f62df515d8bc2 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 19 Jul 2016 11:59:50 +0300 Subject: [PATCH 098/106] Fix: output device now has queue of size 1. a newer command always overrides the previous one --- .../voting/output/AsyncRunnableOutputDevice.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 7a856a0..2946d77 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -11,7 +11,7 @@ import meerkat.voting.output.outputcommands.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ArrayBlockingQueue; /** * This is a base class for simple OutputDevices which run asynchronously (as a separate thread). @@ -21,13 +21,13 @@ import java.util.concurrent.LinkedBlockingQueue; public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, Runnable { private Logger logger; - private LinkedBlockingQueue queue; + private ArrayBlockingQueue queue; private volatile boolean shutDownHasBeenCalled; public AsyncRunnableOutputDevice() { logger = LoggerFactory.getLogger(AsyncRunnableOutputDevice.class); logger.info("AsyncRunnableOutputDevice is constructed"); - queue = new LinkedBlockingQueue<>(); + queue = new ArrayBlockingQueue<>(1); shutDownHasBeenCalled = false; } @@ -87,24 +87,28 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R SignedEncryptedBallot signedEncryptedBallot, FutureCallback callback) { logger.debug("Output interface call to commit to ballot"); + queue.clear(); queue.add(new CommitOutputCommand(plaintextBallot, signedEncryptedBallot, (OutputDeviceCommitCallback)callback)); } @Override public void audit(BallotSecrets ballotSecrets, FutureCallback callback) { logger.debug("an interface call to audit"); + queue.clear(); queue.add(new AuditOutputCommand(ballotSecrets, (OutputDeviceFinalizeCallback)callback)); } @Override public void castBallot(FutureCallback callback) { logger.debug("an interface call to cast ballot"); + queue.clear(); queue.add(new CastOutputCommand((OutputDeviceFinalizeCallback)callback)); } @Override public void cancelBallot(FutureCallback callback) { logger.debug("an interface call to cancel the output"); + queue.clear(); queue.add(new CancelOutputCommand((ControllerCallback)callback)); } From da7a05ecd8fb395f5003e6eb7461cac55a513644 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 19 Jul 2016 12:05:06 +0300 Subject: [PATCH 099/106] Fix: UI now has command queue of size 1. A new CommandPend class is introduced. It functions basically as an ArrayBlockingQueue of size 1. Difference is that it can handle two functions from two different threads - trample(cmd): removes the previously kept command (if there is such) and overrides it with the next command - offer(cmd): keeps the given command, but only if it doesn't currently keeps an older one This new functionality is used so the UI can get commands from the controller (but only take into account the latest one). At the same time it gets tick commands from its clock ticker, but only keep and handle those if it doesn't have a real controller command to handle. --- .../java/meerkat/voting/ui/CommandPend.java | 53 +++++++++++++++++++ .../meerkat/voting/ui/SystemConsoleUI.java | 30 +++++------ .../meerkat/voting/ui/TickerTimerTask.java | 12 ++--- 3 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java diff --git a/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java new file mode 100644 index 0000000..a12d3ac --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/ui/CommandPend.java @@ -0,0 +1,53 @@ +package meerkat.voting.ui; + +import java.util.concurrent.ArrayBlockingQueue; + +/** + * A special kind of an ArrayBlockingQueue. + * It is only of size 1, meaning it keeps only one element at most at every point of time. + * The trample function is similar to put/add except that it overrides the previously kept element. + * Other functions are similar to the matching functions in ArrayBlockingQueue. + * For instance, the offer function only "recommends" another element to keep, but if there is a stored element + * already, than this recommendation is ignored. + */ +public class CommandPend { + + private ArrayBlockingQueue queue; + + public CommandPend () { + queue = new ArrayBlockingQueue<>(1); + } + + /** + * overrides the current kept command + * @param cmd a command to override the previous one (if existed) + */ + synchronized public void trample (T cmd) { + queue.clear(); + queue.add(cmd); + } + + /** + * keeps the offered command, but only if there is no other command to handle right now + * @param cmd a command to keep if we currently do not have another + */ + synchronized public void offer (T cmd) { + queue.offer(cmd); + } + + /** + * Retrieves and removes the kept command, waiting if necessary until a command becomes available. + * @return the kept command + * @throws InterruptedException + */ + public T take() throws InterruptedException { + return queue.take(); + } + + /** + * removes the kept command + */ + synchronized public void clear () { + queue.clear(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java index e35c527..3b34da8 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/SystemConsoleUI.java @@ -8,7 +8,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; import meerkat.voting.controller.callbacks.*; import meerkat.voting.ui.uicommands.*; @@ -27,7 +26,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { private static final Logger logger = LoggerFactory.getLogger(SystemConsoleUI.class); private BufferedReader bufferedReader; - private LinkedBlockingQueue queue; + private CommandPend cmdPend; private Date startWaitingTime; private volatile boolean shutDownHasBeenCalled; @@ -37,30 +36,30 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { final int tickDurationInMillisec = 10; // period between view update calls logger.info("A VB UI console is constructed"); - queue = new LinkedBlockingQueue<>(); + cmdPend = new CommandPend<>(); bufferedReader = new BufferedReader(new InputStreamReader(in)); startWaitingTime = null; Timer timer = new Timer(); - timer.scheduleAtFixedRate(new TickerTimerTask(queue), new Date(), tickDurationInMillisec); + timer.scheduleAtFixedRate(new TickerTimerTask(cmdPend), new Date(), tickDurationInMillisec); shutDownHasBeenCalled = false; } /** - * the run() method. Simply loops and takes commands from the UI's queue and handles them accordingly + * the run() method. Simply loops and takes the UI's pending command and handles it accordingly */ @Override public void run () { logger.info("UI starts running"); while (! wasShutDownCalled()) { try { - UICommand command = queue.take(); + UICommand command = cmdPend.take(); handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); + logger.warn ("Interrupted while reading the pending command " + e); } } } @@ -70,7 +69,8 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { public void callShutDown() { logger.info("callShutDown command has been called"); shutDownHasBeenCalled = true; - queue.clear(); + stopWaiting(); + cmdPend.clear(); } /** @@ -124,7 +124,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void startNewVoterSession(FutureCallback callback) { logger.debug("UI interface call to startNewVoterSession"); - queue.add(new StartSessionUICommand((NewVoterCallback)callback)); + cmdPend.trample(new StartSessionUICommand((NewVoterCallback)callback)); } /** @@ -178,8 +178,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void chooseChannel(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - ChannelChoiceUICommand command = new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback); - queue.add(command); + cmdPend.trample(new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback)); } /** @@ -212,7 +211,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void askVoterQuestions(List questions, FutureCallback> callback) { logger.debug("UI interface call to chooseChannel"); - queue.add(new RaceVotingUICommand(questions, (VotingCallback)callback)); + cmdPend.trample(new RaceVotingUICommand(questions, (VotingCallback)callback)); } /** @@ -244,7 +243,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void castOrAudit(FutureCallback callback) { logger.debug("UI interface call to castOrAudit"); - queue.add(new CastOrAuditUICommand((CastOrAuditCallback)callback)); + cmdPend.trample(new CastOrAuditUICommand((CastOrAuditCallback)callback)); } /** @@ -288,7 +287,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { logger.debug("UI interface call to notifyVoterToWaitForFinish"); - queue.add(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); + cmdPend.trample(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); } /** @@ -331,8 +330,7 @@ public class SystemConsoleUI implements VotingBoothUI, Runnable { @Override public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { logger.debug("UI interface call to showErrorMessageWithButtons"); - queue.clear(); - queue.add(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + cmdPend.trample(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); } /** diff --git a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java index 594fb6e..42924c2 100644 --- a/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java +++ b/voting-booth/src/main/java/meerkat/voting/ui/TickerTimerTask.java @@ -4,22 +4,18 @@ import meerkat.voting.ui.uicommands.TickCommand; import meerkat.voting.ui.uicommands.UICommand; import java.util.TimerTask; -import java.util.concurrent.LinkedBlockingQueue; /** * A thread that sends the UI clock TickCommands in a given constant frequency */ class TickerTimerTask extends TimerTask { - private LinkedBlockingQueue uiQueue; - public TickerTimerTask (LinkedBlockingQueue uiQueue) { - this.uiQueue = uiQueue; + private CommandPend cmdPend; + public TickerTimerTask (CommandPend cmdPend) { + this.cmdPend = cmdPend; } @Override public void run() { - UICommand t = uiQueue.peek(); - if ((t != null) && !(t instanceof TickCommand)) { - uiQueue.add(new TickCommand(null)); - } + cmdPend.offer(new TickCommand(null)); } } From ae357541e833fd964d46c47cc5bcbe77c61a1686 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Wed, 27 Jul 2016 14:25:09 +0300 Subject: [PATCH 100/106] Fix typo in documentation comment --- .../src/main/java/meerkat/crypto/dkg/feldman/Protocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index d81c75a..84cff0b 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -33,7 +33,7 @@ public class Protocol extends VerifiableSecretSharing { Waiting, /** - * Party gave invalid answer to conplaint. + * Party gave invalid answer to complaint. */ Disqualified, From cb65103fcaa84be2f94f5718fb25263e54ff8b31 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 31 Jul 2016 17:43:58 +0300 Subject: [PATCH 101/106] Fix: typo in comment --- .../src/main/java/meerkat/crypto/dkg/feldman/User.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index 6563dfd..f7c4624 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -436,7 +436,7 @@ public class User implements Runnable { /** * complaint message is valid if: * 1. it was received in broadcast chanel - * 2. the sender didn't complained against id before + * 2. the sender didn't complain against id before */ protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){ int i = sender; From aea84d0f543018dea10bb81bddde1899605fcb0e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 31 Jul 2016 17:44:24 +0300 Subject: [PATCH 102/106] Add: todo comments --- .../src/main/java/meerkat/crypto/dkg/feldman/Protocol.java | 1 + .../java/meerkat/crypto/secretsharing/shamir/Polynomial.java | 1 + 2 files changed, 2 insertions(+) diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index 84cff0b..f612b07 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -79,6 +79,7 @@ public class Protocol extends VerifiableSecretSharing { * 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 */ + //TODO: why the use of regular Random? Should it be changed? public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g , Group group, int id, ByteEncoder encoder) { super(t, n, zi, random, q, g,group); diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java index 58f38fb..b00aec5 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/secretsharing/shamir/Polynomial.java @@ -198,6 +198,7 @@ public class Polynomial implements Comparable { @Override public boolean equals(Object obj) { + //TODO: is this implementation correct? cannot understand its logic (hai) if(!super.equals(obj)) return false; Point other = (Point)obj; From afed4fb51003957aeda4abe17f5483f5fd36b06e Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:13:10 +0300 Subject: [PATCH 103/106] Fix: reading protobuf BoolValues through network used to fail due to problematic dynamic casting --- .../src/main/java/meerkat/rest/ProtobufMessageBodyReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java index d09e213..ebf80a0 100644 --- a/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java +++ b/restful-api-common/src/main/java/meerkat/rest/ProtobufMessageBodyReader.java @@ -32,7 +32,7 @@ public class ProtobufMessageBodyReader implements MessageBodyReader { InputStream entityStream) throws IOException, WebApplicationException { try { Method newBuilder = type.getMethod("newBuilder"); - GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type); + Message.Builder builder = (Message.Builder) newBuilder.invoke(type); return builder.mergeFrom(entityStream).build(); } catch (Exception e) { throw new WebApplicationException(e); From c78b78aa3c96c71400d1d2baa26e271c79a67864 Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:22:21 +0300 Subject: [PATCH 104/106] no change --- .../java/meerkat/voting/output/AsyncRunnableOutputDevice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java index 2946d77..0052a2c 100644 --- a/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java +++ b/voting-booth/src/main/java/meerkat/voting/output/AsyncRunnableOutputDevice.java @@ -40,7 +40,7 @@ public abstract class AsyncRunnableOutputDevice implements BallotOutputDevice, R handleSingleCommand(command); } catch (InterruptedException e) { - logger.warn ("Interrupted while reading from command queue " + e); + logger.warn("Interrupted while reading from command queue " + e); } } } From 4ddd5f852a8f6ab07376b08b947b5c9ed3c1cdec Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Tue, 2 Aug 2016 14:24:25 +0300 Subject: [PATCH 105/106] Fix: better test of the NetworkVirtualPrinter --- .../voting/NetworkVirtualPrinterTest.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java index 827bf93..80c9b72 100644 --- a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -37,6 +37,7 @@ public class NetworkVirtualPrinterTest { private static final String SUB_ADDRESS = ""; private static final int PORT = 8080; + private Semaphore semaphore0; private Semaphore semaphore1; private Semaphore semaphore2; private Throwable thrown; @@ -45,6 +46,9 @@ public class NetworkVirtualPrinterTest { private NetworkVirtualPrinter networkPrinter; + + + private class ScanHandler implements FutureCallback { private final ScannedData expectedData; @@ -70,9 +74,11 @@ public class NetworkVirtualPrinterTest { private class CommitHandler extends OutputDeviceCommitCallback { private boolean success; + public String errorMessage; public CommitHandler(int requestId, long serialNumber) { super(requestId, serialNumber, null, null); + errorMessage = null; success = false; } @@ -80,11 +86,13 @@ public class NetworkVirtualPrinterTest { public void onSuccess(Void v) { System.out.println("CommitHandler success"); success = true; + semaphore0.release(); } @Override public void onFailure(Throwable t) { - assertThat("Commit to ballot failed " + t.getMessage(), false); + errorMessage = "Commit to ballot failed " + t.getMessage(); + semaphore0.release(); } public boolean gotSuccess() { @@ -95,9 +103,11 @@ public class NetworkVirtualPrinterTest { private class CastHandler extends OutputDeviceFinalizeCallback { private boolean success; + public String errorMessage; public CastHandler(int requestId, long serialNumber) { super(requestId, serialNumber, null, null); + errorMessage = null; success = false; } @@ -110,8 +120,8 @@ public class NetworkVirtualPrinterTest { @Override public void onFailure(Throwable t) { + errorMessage = "Cast to ballot failed " + t.getMessage(); semaphore1.release(); - assertThat("Cast ballot failed " + t.getMessage(), false); } public boolean gotSuccess() { @@ -126,6 +136,7 @@ public class NetworkVirtualPrinterTest { scanner = new PollingStationWebScanner(PORT, SUB_ADDRESS); + semaphore0 = new Semaphore(0); semaphore1 = new Semaphore(0); semaphore2 = new Semaphore(0); thrown = null; @@ -136,11 +147,11 @@ public class NetworkVirtualPrinterTest { assertThat("Could not start server: " + e.getMessage(), false); } + networkPrinter = new NetworkVirtualPrinter(ADDRESS + ":" + PORT); Thread outputThread = new Thread(networkPrinter); outputThread.setName("Meerkat VB-Output Thread"); outputThread.start(); - } @Test @@ -191,12 +202,14 @@ public class NetworkVirtualPrinterTest { CommitHandler commitHandler = new CommitHandler(0, serialNumber); networkPrinter.commitToBallot(plaintextBallot, signedEncryptedBallot, commitHandler); + + semaphore0.acquire(); + CastHandler castHandler = new CastHandler(1, serialNumber); networkPrinter.castBallot(castHandler); - - semaphore1.acquire(); + semaphore2.acquire(); // Make sure the response was valid From ce40a04ac73db6e6122d070637950f50502d318d Mon Sep 17 00:00:00 2001 From: Hai Brenner Date: Sun, 7 Aug 2016 17:04:23 +0300 Subject: [PATCH 106/106] Make code of SDKG test prettier --- .../meerkat/crypto/dkg/gjkr/SDKGTest.java | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java index e4550f0..d172c23 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java @@ -10,6 +10,7 @@ import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; import meerkat.crypto.utils.BigIntegerByteEncoder; import meerkat.crypto.utils.GenerateRandomPrime; +import meerkat.protobuf.Crypto; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; @@ -20,10 +21,7 @@ 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.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -42,58 +40,57 @@ public class SDKGTest { BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); Group group = new Zpstar(p); Arithmetic arithmetic = new Fp(q); - int t = 1; - int n = 20; + int initialT = 17; + int initialN = 20; Random rand = new Random(1); public void oneTest(Testable testable) throws Exception { - for (int i = 0; i < testable.sdkgs.length ; i++){ + 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(); + for (Future ftr : testable.futures) { + ftr.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)); + BigInteger publicValue = group.multiply(testable.g, testable.secret); + for (int i : testable.valids){ + assertEquals (testable.sdkgs[i-1].getPublicValue(), publicValue); } // assert valid verification values BigInteger expected,verification; - for (int i: testable.valids){ + 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)); + assertEquals (expected, verification); } // restore the secret from shares - ArrayList sharesList = new ArrayList(); + ArrayList sharesList = new ArrayList<>(); - for (int i: testable.valids){ + 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); - } + shares = sharesList.toArray(shares); - BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic); - assert (calculatedSecret.equals(testable.secret)); + BigInteger calculatedSecret = SecretSharing.recoverSecret(shares, arithmetic); + assertEquals (calculatedSecret, testable.secret); } @Test - public void test() throws Exception { + public void runSharingProtocol() throws Exception { Testable testable; for (int i = 0; i < NUM_TESTS; i++) { - testable = new Testable(n, t, group, q, rand); + testable = new Testable(initialN+i, initialT+i, group, q, rand); oneTest(testable); } } + static class Testable { Set valids; Set QUAL; @@ -118,14 +115,14 @@ public class SDKGTest { this.q = q; this.random = random; this.sdkgs = new User[n]; - this.valids = new HashSet(); - this.QUAL = new HashSet(); - this.aborted = new HashSet(); - this.malicious = new HashSet(); + this.valids = new HashSet<>(); + this.QUAL = new HashSet<>(); + this.aborted = new HashSet<>(); + this.malicious = new HashSet<>(); this.futures = new Future[n]; this.g = sampleGenerator(random); - this.h = group.multiply(g,randomIntModQ(random)); - ArrayList ids = new ArrayList(); + this.h = group.multiply(g, randomIntModQ(random)); + List ids = new ArrayList<>(); for (int id = 1; id<= n ; id++){ ids.add(id); } @@ -139,8 +136,8 @@ public class SDKGTest { id = ids.remove(random.nextInt(ids.size())); s = randomIntModQ(random); channel = channels.getChannel(id); - sdkg = new Protocol(t, n, s, random, q, g , h, group, id,encoder); - sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg); + sdkg = new Protocol<>(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); } @@ -159,7 +156,7 @@ public class SDKGTest { case HONEST: valids.add(id); QUAL.add(id); - return new User(sdkg,channel); + return new User<>(sdkg,channel); case FAILSTOP: int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 @@ -167,13 +164,13 @@ public class SDKGTest { if (abortStage > 1){ QUAL.add(id); } - return new SDKGUserImplAbort(sdkg,channel,abortStage); + return new SDKGUserImplAbort(sdkg, channel, abortStage); case MALICIOUS: malicious.add(id); - Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); + Set falls = DKGMaliciousUser.selectFallsRandomly(valids, random); + Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg, channel, random); + return new SDKGMaliciousUserImpl(sdkg, maliciousSDKG, channel, falls); } fail("Unknown user type"); @@ -203,4 +200,6 @@ public class SDKGTest { } } + + }