Browse Source

networking code upload; it doesn't compile yet, and there's a small delta left on the client code before that's ready anyways. But the server code has been drafted; needs to be debugged

tristangurtler 3 years ago
parent
commit
4715de0aad

+ 85 - 7
prsona/inc/networkClient.hpp

@@ -1,16 +1,94 @@
 #ifndef __PRSONA_NETWORK_CLIENT_HPP
 #define __PRSONA_NETWORK_CLIENT_HPP
 
+#include <string>
+#include <sstream>
+#include <cstring>
+#include <cstdio>
 #include "client.hpp"
+#include "CivetServer.h"
 
-class PrsonaNetworkClient : public PrsonaClient {
+#define MG_WEBSOCKET_OPCODE_DATACOMPLETE 0xb
+#define PRSONA_PORT 8080
+#define USE_SSL 0
+
+#define USER_TALLY_URI "/ws?h"
+#define USER_TALLY_COMMIT_URI "/ws?m"
+
+enum RequestType {
+    PRSONA_ADD_CLIENT = 'a',
+    PRSONA_RECEIVE_VOTE,
+    PRSONA_GET_BGN_PUBKEY,
+    PRSONA_GET_NUM_CLIENTS,
+    PRSONA_GET_NUM_SERVERS,
+    PRSONA_GET_VOTES_BY,
+    PRSONA_GET_ALL_VOTES,
+    PRSONA_GET_USER_TALLY,
+    PRSONA_GET_SERVER_TALLY,
+    PRSONA_GET_PSEUDONYMS,
+    PRSONA_GET_VOTE_ROW_COMMITMENT,
+    PRSONA_GET_VOTE_MATRIX_COMMITMENT,
+    PRSONA_GET_USER_TALLY_COMMITMENT,
+    PRSONA_GET_SERVER_TALLY_COMMITMENT,
+    PRSONA_GET_PSEUDONYMS_COMMITMENT,
+    PRSONA_GET_BGN_DETAILS,
+    PRSONA_ADD_CURR_SEED_TO_GENERATOR,
+    PRSONA_SET_FRESH_GENERATOR,
+    PRSONA_ADD_RAND_SEED_TO_GENERATOR,
+    PRSONA_SET_EG_BLIND_GENERATOR,
+    PRSONA_EPOCH_BUILD_UP,
+    PRSONA_EPOCH_BREAK_DOWN,
+    PRSONA_EPOCH_UPDATE,
+    PRSONA_NEW_USER_UPDATE,
+    PRSONA_GET_PARTIAL_DECRYPTION,
+    PRSONA_RECEIVE_PARTIAL_DECRYPTION,
+    PRSONA_GET_FRESH_GENERATOR = '-',
+    PRSONA_GET_EG_BLIND_GENERATOR ='_',
+    PRSONA_RECEIVE_FRESH_GENERATOR = 'a',
+    PRSONA_RECEIVE_VOTE_TALLY,
+    PRSONA_RECEIVE_NEW_USER_DATA,
+    PRSONA_VERIFY_REPUTATION_PROOF
+};
+
+struct synchronization_tool {
+    std::mutex mtx;
+    std::condition_variable cv;
+    size_t val, val2;
+};
+
+class PrsonaClientWebSocketHandler : public CivetWebSocketHandler {
     public:
         // CONSTRUCTORS
-        PrsonaNetworkClient(
-            const std::vector<Proof>& generatorProof,
-            const Twistpoint& elGamalBlindGenerator,
-            const BGNPublicKey& serverPublicKey,
-            const size_t numServers);
-}; 
+        PrsonaClientWebSocketHandler(
+            const PrsonaClient *prsonaClient, 
+            const std::vector<std::string> serverIPs,
+            const std::string selfIP);
+
+        virtual bool handleConnection(
+            CivetServer *server,
+            const struct mg_connection *conn);
+
+        virtual void handleReadyState(
+            CivetServer *server,
+            struct mg_connection *conn);
+
+        virtual bool handleData(
+            CivetServer *server,
+            struct mg_connection *conn,
+            int bits,
+            char *data,
+            size_t data_len);
+
+        virtual void handleClose(
+            CivetServer *server,
+            const struct mg_connection *conn);
+
+    private:
+        const PrsonaClient *prsonaClient;
+        const std::vector<std::string> serverIPs;
+        const std::string selfIP;
+
+        void verify_reputation_proof(struct mg_connection *c) const;
+}
 
 #endif

+ 180 - 3
prsona/inc/networkServer.hpp

@@ -1,13 +1,190 @@
 #ifndef __PRSONA_NETWORK_SERVER_HPP
 #define __PRSONA_NETWORK_SERVER_HPP
 
+#include <string>
+#include <sstream>
+#include <cstring>
+#include <cstdio>
 #include "server.hpp"
+#include "CivetServer.h"
 
-class PrsonaNetworkServer : public PrsonaServer {
+#define MG_WEBSOCKET_OPCODE_DATACOMPLETE 0xb
+#define UPDATE_LOCK_URI "/lock"
+#define UPDATE_UNLOCK_URI "/unlock"
+#define GIVE_NEW_VOTE_URI "/ws?b"
+#define ACCEPT_EPOCH_UPDATES_URI "/ws?w"
+#define GIVE_NEW_USER_URI "/ws?x"
+#define PRSONA_PORT 8080
+#define USE_SSL 0
+
+enum RequestType {
+    PRSONA_ADD_CLIENT = 'a',
+    PRSONA_RECEIVE_VOTE,
+    PRSONA_GET_BGN_PUBKEY,
+    PRSONA_GET_NUM_CLIENTS,
+    PRSONA_GET_NUM_SERVERS,
+    PRSONA_GET_VOTES_BY,
+    PRSONA_GET_ALL_VOTES,
+    PRSONA_GET_USER_TALLY,
+    PRSONA_GET_SERVER_TALLY,
+    PRSONA_GET_PSEUDONYMS,
+    PRSONA_GET_VOTE_ROW_COMMITMENT,
+    PRSONA_GET_VOTE_MATRIX_COMMITMENT,
+    PRSONA_GET_USER_TALLY_COMMITMENT,
+    PRSONA_GET_SERVER_TALLY_COMMITMENT,
+    PRSONA_GET_PSEUDONYMS_COMMITMENT,
+    PRSONA_GET_BGN_DETAILS,
+    PRSONA_ADD_CURR_SEED_TO_GENERATOR,
+    PRSONA_SET_FRESH_GENERATOR,
+    PRSONA_ADD_RAND_SEED_TO_GENERATOR,
+    PRSONA_SET_EG_BLIND_GENERATOR,
+    PRSONA_EPOCH_BUILD_UP,
+    PRSONA_EPOCH_BREAK_DOWN,
+    PRSONA_EPOCH_UPDATE,
+    PRSONA_NEW_USER_UPDATE,
+    PRSONA_GET_PARTIAL_DECRYPTION,
+    PRSONA_RECEIVE_PARTIAL_DECRYPTION,
+    PRSONA_GET_FRESH_GENERATOR = '-',
+    PRSONA_GET_EG_BLIND_GENERATOR ='_',
+    PRSONA_RECEIVE_FRESH_GENERATOR = 'a',
+    PRSONA_RECEIVE_VOTE_TALLY,
+    PRSONA_RECEIVE_NEW_USER_DATA,
+    PRSONA_VERIFY_REPUTATION_PROOF
+};
+
+struct synchronization_tool {
+    std::mutex mtx;
+    std::condition_variable cv;
+    size_t val, val2;
+};
+
+static int synchro_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data);
+
+static void synchro_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data);
+
+static int empty_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{ return false; }
+
+static void empty_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data)
+{ /* */ }
+
+void obtain_update_locks(
+    std::unique_lock<std::mutex> &lck,
+    const std::vector<std::string>& serverIPs,
+    const std::string& selfIP,
+    struct synchronization_tool *synch);
+
+void release_update_locks(
+    std::unique_lock<std::mutex> &lck,
+    const std::vector<std::string>& serverIPs,
+    const std::string& selfIP,
+    struct synchronization_tool *synch);
+
+std::string make_epoch_initiator_string(
+    std::vector<Proof> generatorProof,
+    Twistpoint nextGenerator);
+
+std::string make_epoch_update_string(
+    std::vector<std::vector<Proof>> pi,
+    std::vector<std::vector<Twistpoint>> permutationCommits,
+    std::vector<std::vector<Twistpoint>> freshPseudonymCommits,
+    std::vector<std::vector<Twistpoint>> freshPseudonymSeedCommits,
+    std::vector<std::vector<CurveBipoint>> serverTallyCommits,
+    std::vector<std::vector<std::vector<TwistBipoint>>> partwayVoteMatrixCommits,
+    std::vector<std::vector<std::vector<TwistBipoint>>> finalVoteMatrixCommits,
+    std::vector<std::vector<Twistpoint>> userTallyMaskCommits,
+    std::vector<std::vector<Twistpoint>> userTallyMessageCommits,
+    std::vector<std::vector<Twistpoint>> userTallySeedCommits,
+    Twistpoint nextGenerator,
+    bool doUserTallies);
+
+class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
     public:
         // CONSTRUCTORS
-        PrsonaNetworkServer(size_t numServers);
-        PrsonaNetworkServer(size_t numServers, const BGN& other_bgn);
+        PrsonaServerWebSocketHandler(
+            const PrsonaServer *prsonaServer, 
+            const std::mutex *updateMtx,
+            const std::vector<std::string> serverIPs,
+            const std::string selfIP);
+
+        virtual bool handleConnection(
+            CivetServer *server,
+            const struct mg_connection *conn);
+
+        virtual void handleReadyState(
+            CivetServer *server,
+            struct mg_connection *conn);
+
+        virtual bool handleData(
+            CivetServer *server,
+            struct mg_connection *conn,
+            int bits,
+            char *data,
+            size_t data_len);
+
+        virtual void handleClose(
+            CivetServer *server,
+            const struct mg_connection *conn);
+
+    private:
+        const PrsonaServer *prsonaServer;
+        const std::mutex *updateMtx;
+        const size_t *epochNum;
+        const std::vector<std::string> serverIPs;
+        const std::string selfIP;
+
+        struct synchronization_tool updateSynch, distributeSynch;
+
+        // BASIC PUBLIC SYSTEM INFO GETTERS
+        void get_bgn_public_key(struct mg_connection *c) const;
+        void get_num_clients(struct mg_connection *c) const;
+        void get_num_servers(struct mg_connection *c) const;
+
+        // ENCRYPTED DATA GETTERS
+        void get_current_votes_by(struct mg_connection *c) const;
+        void get_all_current_votes(struct mg_connection *c) const;
+        void get_current_user_encrypted_tally(struct mg_connection *c) const;
+        void get_current_server_encrypted_tally(struct mg_connection *c) const;
+        void get_current_pseudonyms(struct mg_connection *c) const;
+
+        // PROOF COMMITMENT GETTERS
+        void get_vote_row_commitment(struct mg_connection *c) const;
+        void get_vote_matrix_commitment(struct mg_connection *c) const;
+        void get_user_tally_commitment(struct mg_connection *c) const;
+        void get_server_tally_commitment(struct mg_connection *c) const;
+        void get_pseudonyms_commitment(struct mg_connection *c) const;
+
+        // CLIENT INTERACTIONS
+        void add_new_client(struct mg_connection *c);
+        void receive_vote(struct mg_connection *c);
+
+        // CONSTRUCTOR HELPERS
+        void get_bgn_details(struct mg_connection *c) const;
+        void initialize_fresh_generator(struct mg_connection *c);
+        void add_rand_seed_to_generator(struct mg_connection *c) const;
+        void set_EG_blind_generator(struct mg_connection *c);
+
+        // EPOCH ROUNDS
+        void build_up_midway_pseudonyms(struct mg_connection *c);
+        void break_down_midway_pseudonyms(struct mg_connection *c);
+        void accept_epoch_updates(struct mg_connection *c);
+
+        // DATA MAINTENANCE
+        void import_new_user_update(struct mg_connection *c);
 }; 
 
 #endif

+ 211 - 0
prsona/src/clientMain.cpp

@@ -0,0 +1,211 @@
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <cstdlib>
+#include <vector>
+#include <string>
+
+#include "networkClient.hpp"
+
+#define EPOCH_URI "/epoch"
+#define EXIT_URI "/exit"
+#define BGN_URI "/ws?c"
+#define BLIND_GEN_URI "/ws?_"
+
+#define BGN_TMP_FILE "~/tmp/bgn"
+#define GEN_TMP_FILE "~/tmp/generator"
+
+using namespace std;
+
+struct synchronization_tool exitSync, bgnSync, generatorSync;
+
+size_t epochNum = 0;
+
+// Initialize the classes we use
+void initialize_prsona_classes()
+{
+    Scalar::init();
+    PrsonaBase::init();
+    PrsonaBase::set_client_malicious();
+}
+
+PrsonaClient *create_client_from_files(size_t numServers)
+{
+    unique_lock<mutex> lck1(bgnSync.mtx);
+    ifstream bgnFile(BGN_TMP_FILE);
+    BGNPublicKey publicKey;
+    bgnFile >> publicKey;
+    lck1.unlock();
+
+    unique_lock<mutex> lck2(generatorSync.mtx);
+    ifstream genFile(GEN_TMP_FILE);
+    vector<Proof> pi;
+    Twistpoint generator;
+
+    size_t sizeOfPi;
+    genFile >> sizeOfPi;
+    for (size_t i = 0; i < sizeOfPi; i++)
+    {
+        Proof currProof;
+        genFile >> currProof;
+        pi.push_back(currProof);
+    }
+    genFile >> generator;
+
+    return new PrsonaClient(pi, generator, publicKey, numServers);
+}
+
+PrsonaClient *create_client(size_t numServers)
+{
+    struct mg_connection *conn = mg_connect_websocket_client(
+        serverIPs[0].c_str(),
+        PRSONA_PORT,
+        USE_SSL,
+        NULL,
+        0,
+        BGN_URI,
+        "null",
+        bgn_websocket_data_handler,
+        bgn_websocket_close_handler,
+        NULL);
+
+    if (!conn)
+    {
+        cerr << "Couldn't obtain BGN details" << endl;
+        return 1;
+    }
+
+    unique_lock<mutex> lck1(bgnSync.mtx);
+    remove(BGN_TMP_FILE);
+    bgnSync.val = 0;
+    mg_websocket_client_write(
+        conn,
+        MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+        "",
+        0);
+
+    while (!bgnSync.val)
+        bgnSync.cv.wait(lck1);
+
+    lck1.unlock();
+
+    struct mg_connection *conn = mg_connect_websocket_client(
+        serverIPs[0].c_str(),
+        PRSONA_PORT,
+        USE_SSL,
+        NULL,
+        0,
+        BLIND_GEN_URI,
+        "null",
+        blind_gen_websocket_data_handler,
+        blind_gen_websocket_close_handler,
+        NULL);
+
+    if (!conn)
+    {
+        cerr << "Couldn't obtain BGN details" << endl;
+        return 1;
+    }
+
+    unique_lock<mutex> lck2(generatorSync.mtx);
+    remove(GEN_TMP_FILE);
+    generatorSync.val = 0;
+    mg_websocket_client_write(
+        conn,
+        MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+        "",
+        0);
+
+    while (!generatorSync.val)
+        generatorSync.cv.wait(lck2);
+
+    lck2.unlock();
+
+    return create_client_from_files(numServers);
+}
+
+int main(int argc, char *argv[])
+{
+    initialize_prsona_classes();
+
+#if USE_SSL
+    mg_init_library(0);
+#else
+    mg_init_library(MG_FEATURES_SSL);
+#endif
+    
+    const char *options[] = {"listening_ports", PRSONA_PORT, 0};
+
+    vector<string> serverIPs, clientIPs;
+    string selfIP;
+
+    char buffer[40];
+    ifstream serverConfig("serverIPs.cfg");
+    while (!serverConfig.eof())
+    {
+        serverConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            serverIPs.push_back(string(buffer));
+    }
+
+    ifstream clientConfig("clientIPs.cfg");
+    while (!clientConfig.eof())
+    {
+        clientConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            clientIPs.push_back(string(buffer));
+    }
+
+    ifstream selfConfig("selfIP.cfg");
+    while (!selfConfig.eof())
+    {
+        selfConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            selfIP = buffer;
+    }
+
+    // Defaults
+    size_t numServers = serverIPs.size();
+    size_t numClients = clientIPs.size();
+    bool maliciousServers = true;
+
+    if (argc > 1)
+    {
+        bool setting = argv[1][0] == 't' || argv[1][0] == 'T';
+        maliciousServers = setting;
+    }
+
+    cout << "Establishing PRSONA client with the following parameters: " << endl;
+    cout << numServers << " PRSONA servers" << endl;
+    cout << numClients << " PRSONA clients" << endl;
+    cout << "Servers are set to " << (maliciousServers ? "MALICIOUS" : "HBC") << " security" << endl;
+    cout << "This client is at IP address: " << selfIP << endl;
+    cout << endl;
+
+    // Set malicious flags where necessary
+    if (maliciousServers)
+        PrsonaBase::set_server_malicious();
+
+    // Entities we operate with
+    PrsonaClient *prsonaClient = create_client(numServers);
+    CivetServer server(options);
+
+    PrsonaClientWebSocketHandler wsHandler(prsonaClient, &updateMtx, &epochNum, serverIPs, selfIP);
+    server.addWebSocketHandler("/ws", wsHandler);
+
+    ExitHandler exitHandler;
+    server.addHandler(EXIT_URI, exitHandler);
+
+    unique_lock<mutex> lck(exitSync.mtx);
+    while (!exitSync.val)
+        exitSync.cv.wait(lck);
+
+    mg_exit_library();
+
+    delete prsonaClient;
+
+    return 0;
+}

+ 270 - 6
prsona/src/networkClient.cpp

@@ -1,9 +1,273 @@
 #include "networkClient.hpp"
 
-PrsonaNetworkClient::PrsonaNetworkClient(
-    const std::vector<Proof>& generatorProof,
-    const Twistpoint& elGamalBlindGenerator,
-    const BGNPublicKey& serverPublicKey,
-    size_t numServers)
-: PrsonaClient(generatorProof, elGamalBlindGenerator, serverPublicKey, numServers)
+std::string random_string(size_t length)
+{
+    auto randchar = []() -> char
+    {
+        const char charset[] =
+        "0123456789_-"
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrstuvwxyz";
+        const size_t max_index = (sizeof(charset) - 1);
+        return charset[ rand() % max_index ];
+    };
+    std::string str(length,0);
+    std::generate_n(str.begin(), length, randchar);
+    return str;
+}
+
+PrsonaClientWebSocketHandler::PrsonaClientWebSocketHandler(
+    const PrsonaClient *prsonaClient, 
+    const std::vector<std::string> serverIPs,
+    const std::string selfIP)
+: prsonaClient(prsonaClient), serverIPs(serverIPs), selfIP(selfIP)
 { /* */ }
+
+virtual bool PrsonaClientWebSocketHandler::handleConnection(
+    CivetServer *server,
+    const struct mg_connection *conn)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+    
+    flag = (info->query_string && info->query_string[0] == PRSONA_VERIFY_REPUTATION_PROOF);
+
+    return flag;
+}
+
+void PrsonaServerWebSocketHandler::set_temp_filename(
+    struct mg_connection *conn) const
+{
+    std::string filename = random_string(TMP_FILE_SIZE);
+    
+    char *c_filename = new char[TMP_FILE_SIZE+TMP_DIR_SIZE+1];
+    strncpy(c_filename, TMP_DIR, TMP_DIR_SIZE);
+    for (size_t i = 0; i < TMP_FILE_SIZE; i++)
+        c_filename[i + TMP_DIR_SIZE] = filename[i];
+    c_filename[TMP_DIR_SIZE + TMP_FILE_SIZE] = 0;
+
+    mg_set_user_connection_data(conn, c_filename);
+}
+
+virtual void PrsonaClientWebSocketHandler::handleReadyState(
+    CivetServer *server,
+    struct mg_connection *conn)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+
+    switch (info->query_string[0])
+    {
+        case PRSONA_VERIFY_REPUTATION_PROOF:
+            set_temp_filename(conn);
+            break;
+
+        default:
+            mg_set_user_connection_data(conn, NULL);
+            break;
+    }
+}
+
+virtual bool PrsonaClientWebSocketHandler::handleData(
+    CivetServer *server,
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len)
+{
+    char *filename = (char *) mg_get_user_connection_data(conn);
+
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+    {
+        generate_response(conn, filename);
+        return false;
+    }
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    FILE *currFile = fopen(filename, "ab");
+    fwrite(data, sizeof(char), data_len, currFile);
+    fclose(currFile);
+
+    return true;
+}
+
+void PrsonaServerWebSocketHandler::generate_response(
+    struct mg_connection *conn,
+    char *filename)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+
+    switch (info->query_string[0])
+    {
+        case PRSONA_VERIFY_REPUTATION_PROOF:
+            verify_reputation_proof(conn, filename);
+            break;
+
+        default:
+            break;
+    }
+}
+
+virtual void PrsonaClientWebSocketHandler::handleClose(
+    CivetServer *server,
+    const struct mg_connection *conn)
+{
+    char *filename = (char *) mg_get_user_connection_data(conn);
+    if (!filename)
+        return;
+
+    remove(filename);
+    delete filename;
+}
+
+EGCiphertext PrsonaClientWebSocketHandler::get_first_encrypted_score(
+    const std::string& server,
+    Proof& pi,
+    const Twistpoint& shortTermPublicKey) const
+{
+    struct synchronization_tool synch;
+    std::unique_lock<std::mutex> lck(synch.mtx, std::defer_lock);
+
+    bool flag = false;
+    while (!flag)
+    {
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                server.c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                USER_TALLY_URI,
+                "null",
+                score_websocket_data_handler,
+                score_websocket_close_handler,
+                (void *) &synch);
+
+        if (!conn)
+        {
+            std::cerr << "Trouble getting encrypted score from server at " << recipient << std::endl;
+            continue;
+        }
+
+        lck.lock();
+        synch.val = 0;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        flag = true;
+    }
+
+    while (!synch.val)
+        synch.cv.wait(lck)
+
+    // TODO: Finish retrieving first score
+}
+
+void PrsonaClientWebSocketHandler::get_additional_commitment(
+    const std::vector<std::string>& server,
+    std::vector<Proof>& pi,
+    const Twistpoint& shortTermPublicKey) const
+{
+    bool flag = false;
+    while (!flag)
+    {
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                server.c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                USER_TALLY_COMMIT_URI,
+                "null",
+                synchro_websocket_data_handler,
+                empty_websocket_close_handler,
+                (void *) synch);
+
+        if (!conn)
+        {
+            std::cerr << "Trouble getting encrypted score commitment from server at " << recipient << std::endl;
+            continue;
+        }
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        flag = true;
+    }  
+
+    // TODO: Finish retrieving rest of score commitments
+}
+
+EGCiphertext PrsonaClientWebSocketHandler::get_encrypted_score(
+    std::vector<Proof>& pi,
+    const Twistpoint& shortTermPublicKey) const
+{
+    pi.clear();
+
+    Proof firstProof;
+    EGCiphertext retval =
+        get_first_encrypted_score(
+            serverIPs[0], firstProof, shortTermPublicKey);
+
+    pi.push_back(firstProof);
+
+    get_additional_commitment(serverIPs, pi, shortTermPublicKey);
+
+    return retval;
+}
+
+void PrsonaClientWebSocketHandler::verify_reputation_proof(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    std::vector<Proof> pi;
+    Twistpoint shortTermPublicKey;
+    Scalar threshold;
+
+    size_t sizeOfVector;
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        Proof currProof;
+        file >> currProof;
+        pi.push_back(currProof);
+    }
+    file >> shortTermPublicKey;
+    file >> threshold;
+
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        CurveBipoint currScore;
+        file >> currScore;
+        serverScores.push_back(currScore);
+    }
+
+    std::vector<Proof> encryptedScoreProof;
+    EGCiphertext encryptedScore =
+        get_encrypted_score(encryptedScoreProof);
+
+    bool flag =
+        prsonaClient->verify_reputation_proof(
+            pi,
+            shortTermPublicKey,
+            threshold,
+            encryptedScoreProof,
+            encryptedScore);
+
+    string data = flag ? "\x01" : "\x00";
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), 1);
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}

+ 1655 - 8
prsona/src/networkServer.cpp

@@ -1,15 +1,1662 @@
+#include <iostream>
+
 #include "networkServer.hpp"
 
+#define TMP_FILE_SIZE 12
+#define TMP_DIR "~/tmp/"
+#define TMP_DIR_SIZE 6
+
+std::string random_string(size_t length)
+{
+    auto randchar = []() -> char
+    {
+        const char charset[] =
+        "0123456789_-"
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrstuvwxyz";
+        const size_t max_index = (sizeof(charset) - 1);
+        return charset[ rand() % max_index ];
+    };
+    std::string str(length,0);
+    std::generate_n(str.begin(), length, randchar);
+    return str;
+}
+
+static int synchro_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE)
+        return false;
+
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+    {
+        struct synchronization_tool *synch = (struct synchronization_tool *) user_data;
+
+        unique_lock<mutex> lck(synch->mtx);
+        synch->val++;
+
+        return false;
+    }
+
+    std::cerr << "Unknown response when trying to get update lock." << std::endl;
+    return false;    
+}
+
+static void synchro_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data)
+{
+    struct synchronization_tool *synch = (struct synchronization_tool *) user_data;
+
+    unique_lock<mutex> lck(synch->mtx);
+    synch->val2 = 0;
+    synch->cv.notify_all();
+}
+
+void obtain_update_locks(
+    std::unique_lock<std::mutex> &lck,
+    const std::vector<std::string>& serverIPs,
+    const std::string& selfIP,
+    struct synchronization_tool *synch)
+{
+    size_t i = 0;
+    while (i < serverIPs.size())
+    {
+        if (serverIPs[i] == selfIP)
+        {
+            lck.lock();
+            i++;
+            continue;
+        }
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                UPDATE_LOCK_URI,
+                "null",
+                synchro_websocket_data_handler,
+                synchro_websocket_close_handler,
+                (void *) synch);
+
+        if (!conn)
+        {
+            std::cerr << "Couldn't get server " << i << "'s lock" << std::endl;
+            continue;
+        }
+
+        unique_lock<mutex> lck(synch->mtx);
+        synch->val = 0;
+        synch->val2 = 1;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        while (synch->val2)
+            synch->cv.wait(lck);
+
+        if (synch->val)
+            i++;
+    }
+}
+
+void release_update_locks(
+    std::unique_lock<std::mutex> &lck,
+    const std::vector<std::string>& serverIPs,
+    const std::string& selfIP,
+    struct synchronization_tool *synch)
+{
+    ssize_t i = serverIPs.size() - 1;
+    while (i >= 0)
+    {
+        if (serverIPs[i] == selfIP)
+        {
+            lck.unlock();
+            i--;
+            continue;
+        }
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                UPDATE_UNLOCK_URI,
+                "null",
+                synchro_websocket_data_handler,
+                synchro_websocket_close_handler,
+                (void *) synch);
+
+        if (!conn)
+        {
+            std::cerr << "Couldn't get server " << i << "'s lock" << std::endl;
+            continue;
+        }
+
+        unique_lock<mutex> lck(synch->mtx);
+        synch->val = 0;
+        synch->val2 = 1;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        while (synch->val2)
+            synch->cv.wait(lck);
+
+        if (synch->val)
+            i--;
+    }
+}
+
+std::string make_epoch_initiator_string(
+    const std::vector<Proof>& generatorProof,
+    const Twistpoint& nextGenerator)
+{
+    stringstream buffer;
+    
+    buffer << generatorProof.size();
+    for (size_t i = 0; i < generatorProof.size(); i++)
+        buffer << generatorProof[i];
+    
+    buffer << nextGenerator;
+
+    return buffer.str();
+}
+
+void read_epoch_initiator_string(
+    const char *filename,
+    std::vector<Proof>& generatorProof,
+    Twistpoint& nextGenerator)
+{
+    ifstream file(filename);
+    size_t limitI;
+
+    generatorProof.clear();
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        Proof currProof;
+        file >> currProof;
+        generatorProof.push_back;
+    }
+    
+    file >> nextGenerator;
+}
+
+std::string make_epoch_update_string(
+    const std::vector<std::vector<Proof>>& pi,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& freshPseudonymCommits,
+    const std::vector<std::vector<Twistpoint>>& freshPseudonymSeedCommits,
+    const std::vector<std::vector<CurveBipoint>>& serverTallyCommits,
+    const std::vector<std::vector<std::vector<TwistBipoint>>>& partwayVoteMatrixCommits,
+    const std::vector<std::vector<std::vector<TwistBipoint>>>& finalVoteMatrixCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
+    const Twistpoint& nextGenerator,
+    bool doUserTallies)
+{
+    stringstream buffer;
+    
+    buffer << pi.size();
+    for (size_t i = 0; i < pi.size(); i++)
+    {
+        buffer << pi[i].size();
+        for (size_t j = 0; j < pi[i].size(); j++)
+            buffer << pi[i][j];
+    }
+
+    buffer << permutationCommits.size();
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            buffer << permutationCommits[i][j];
+
+    buffer << freshPseudonymCommits.size();
+    for (size_t i = 0; i < freshPseudonymCommits.size(); i++)
+        for (size_t j = 0; j < freshPseudonymCommits[i].size(); j++)
+            buffer << freshPseudonymCommits[i][j];
+
+    buffer << freshPseudonymSeedCommits.size();
+    for (size_t i = 0; i < freshPseudonymSeedCommits.size(); i++)
+        for (size_t j = 0; j < freshPseudonymSeedCommits[i].size(); j++)
+            buffer << freshPseudonymSeedCommits[i][j];
+
+    buffer << serverTallyCommits.size();
+    for (size_t i = 0; i < serverTallyCommits.size(); i++)
+        for (size_t j = 0; j < serverTallyCommits[i].size(); j++)
+            buffer << serverTallyCommits[i][j];
+
+    buffer << partwayVoteMatrixCommits.size();
+    for (size_t i = 0; i < partwayVoteMatrixCommits.size(); i++)
+        for (size_t j = 0; j < partwayVoteMatrixCommits[i].size(); j++)
+            for (size_t k = 0; k < partwayVoteMatrixCommits[i][j].size(); k++)
+                buffer << partwayVoteMatrixCommits[i][j][k];
+
+    buffer << finalVoteMatrixCommits.size();
+    for (size_t i = 0; i < finalVoteMatrixCommits.size(); i++)
+        for (size_t j = 0; j < finalVoteMatrixCommits[i].size(); j++)
+            for (size_t k = 0; k < finalVoteMatrixCommits[i][j].size(); k++)
+                buffer << finalVoteMatrixCommits[i][j][k];
+
+    buffer << userTallyMaskCommits.size();
+    for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
+            buffer << userTallyMaskCommits[i][j];
+
+    buffer << userTallyMessageCommits.size();
+    for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
+            buffer << userTallyMessageCommits[i][j];
+
+    buffer << userTallySeedCommits.size();
+    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
+        for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
+            buffer << userTallySeedCommits[i][j];
+
+    buffer << nextGenerator;
+    buffer << doUserTallies;
+
+    return buffer.str();
+}
+
+bool read_epoch_update_string(
+    const char *filename,
+    std::vector<std::vector<Proof>>& pi,
+    std::vector<std::vector<Twistpoint>>& permutationCommits,
+    std::vector<std::vector<Twistpoint>>& freshPseudonymCommits,
+    std::vector<std::vector<Twistpoint>>& freshPseudonymSeedCommits,
+    std::vector<std::vector<CurveBipoint>>& serverTallyCommits,
+    std::vector<std::vector<std::vector<TwistBipoint>>>& partwayVoteMatrixCommits,
+    std::vector<std::vector<std::vector<TwistBipoint>>>& finalVoteMatrixCommits,
+    std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
+    std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
+    std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
+    Twistpoint& nextGenerator)
+{
+    ifstream file(filename);
+    size_t limitI, limitJ;
+    
+    pi.clear();
+    permutationCommits.clear();
+    freshPseudonymCommits.clear();
+    freshPseudonymSeedCommits.clear();
+    serverTallyCommits.clear();
+    partwayVoteMatrixCommits.clear();
+    finalVoteMatrixCommits.clear();
+    userTallyMaskCommits.clear();
+    userTallyMessageCommits.clear();
+    userTallySeedCommits.clear();
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Proof> currRow;
+
+        file >> limitJ;
+        for (size_t j = 0; j < limitJ; j++)
+        {
+            Proof currProof;
+            file >> currProof;
+            currRow.push_back(currProof);
+        }
+
+        pi.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        permutationCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        freshPseudonymCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        freshPseudonymSeedCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<CurveBipoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            CurveBipoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        serverTallyCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<std::vector<TwistBipoint>> currMatrix;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            std::vector<TwistBipoint> currRow;
+            for (size_t k = 0; k < limitI; k++)
+            {
+                TwistBipoint currCommit;
+                file >> currCommit;
+                currRow.push_back(currCommit);    
+            }
+            currMatrix.push_back(currRow);
+        }
+        partwayVoteMatrixCommits.push_back(currMatrix);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<std::vector<TwistBipoint>> currMatrix;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            std::vector<TwistBipoint> currRow;
+            for (size_t k = 0; k < limitI; k++)
+            {
+                TwistBipoint currCommit;
+                file >> currCommit;
+                currRow.push_back(currCommit);    
+            }
+            currMatrix.push_back(currRow);
+        }
+        finalVoteMatrixCommits.push_back(currMatrix);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        userTallyMaskCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        userTallyMessageCommits.push_back(currRow);
+    }
+
+    file >> limitI;
+    for (size_t i = 0; i < limitI; i++)
+    {
+        std::vector<Twistpoint> currRow;
+        for (size_t j = 0; j < limitI; j++)
+        {
+            Twistpoint currCommit;
+            file >> currCommit;
+            currRow.push_back(currCommit);
+        }
+        userTallySeedCommits.push_back(currRow);
+    }
+
+    file >> nextGenerator;
+    
+    bool doUserTallies;
+    file >> doUserTallies;
+
+    return doUserTallies;
+}
+
+void distribute_epoch_updates(
+    const std::string& recipient,
+    const std::string& data,
+    const struct synchronization_tool* synch)
+{
+    bool flag = false;
+    while (!flag)
+    {
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                ACCEPT_EPOCH_UPDATES_URI,
+                "null",
+                synchro_websocket_data_handler,
+                empty_websocket_close_handler,
+                (void *) synch);
+
+        if (!conn)
+        {
+            std::cerr << "Trouble giving epoch updates to server at " << recipient << std::endl;
+            continue;
+        }
+        
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        flag = true;
+    }   
+}
+
 /*
  * CONSTRUCTORS
  */
 
-// Used to generate the first server; instantiates BGN for the first time
-PrsonaNetworkServer::PrsonaNetworkServer(size_t numServers)
-: PrsonaServer(numServers)
-{ /* Do nothing */ }
+PrsonaServerWebSocketHandler::PrsonaServerWebSocketHandler(
+    const PrsonaServer *prsonaServer,
+    const std::mutex *updateMtx,
+    const size_t *epochNum,
+    const std::vector<std::string> &serverIPs,
+    const std::string &selfIP)
+: prsonaServer(prsonaServer), updateMtx(updateMtx), epochNum(epochNum),
+    serverIPs(serverIPs), selfIP(selfIP)
+{ /* */ }
+
+virtual bool PrsonaServerWebSocketHandler::handleConnection(
+    CivetServer *server,
+    const struct mg_connection *conn)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+    
+    bool flag = info->query_string && info->query_string[0] >= PRSONA_ADD_CLIENT && info->query_string[0] <= PRSONA_RECEIVE_PARTIAL_DECRYPTION;
+    flag = flag || (info->query_string && info->query_string[0] == PRSONA_GET_FRESH_GENERATOR);
+    flag = flag || (info->query_string && info->query_string[0] == PRSONA_GET_EG_BLIND_GENERATOR);
+
+    return flag;
+}
+
+void PrsonaServerWebSocketHandler::set_temp_filename(
+    struct mg_connection *conn) const
+{
+    std::string filename = random_string(TMP_FILE_SIZE);
+    
+    char *c_filename = new char[TMP_FILE_SIZE+TMP_DIR_SIZE+1];
+    strncpy(c_filename, TMP_DIR, TMP_DIR_SIZE);
+    for (size_t i = 0; i < TMP_FILE_SIZE; i++)
+        c_filename[i + TMP_DIR_SIZE] = filename[i];
+    c_filename[TMP_DIR_SIZE + TMP_FILE_SIZE] = 0;
+
+    mg_set_user_connection_data(conn, c_filename);
+}
+
+virtual void PrsonaServerWebSocketHandler::handleReadyState(
+    CivetServer *server,
+    struct mg_connection *conn)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+
+    switch (info->query_string[0])
+    {
+        case PRSONA_ADD_CLIENT:
+        case PRSONA_RECEIVE_VOTE:
+        case PRSONA_GET_VOTES_BY:
+        case PRSONA_GET_USER_TALLY:
+        case PRSONA_GET_SERVER_TALLY:
+        case PRSONA_GET_VOTE_ROW_COMMITMENT:
+        case PRSONA_GET_USER_TALLY_COMMITMENT:
+        case PRSONA_GET_SERVER_TALLY_COMMITMENT:
+        case PRSONA_ADD_CURR_SEED_TO_GENERATOR:
+        case PRSONA_SET_FRESH_GENERATOR:
+        case PRSONA_ADD_RAND_SEED_TO_GENERATOR:
+        case PRSONA_SET_EG_BLIND_GENERATOR:
+        case PRSONA_EPOCH_UPDATE:
+        case PRSONA_NEW_USER_UPDATE:
+        case PRSONA_RECEIVE_PARTIAL_DECRYPTION:
+            set_temp_filename(conn);
+            break;
+
+        default:
+            mg_set_user_connection_data(conn, NULL);
+            break;
+    }
+}
+
+virtual bool PrsonaServerWebSocketHandler::handleData(
+    CivetServer *server,
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len)
+{
+    char *filename = (char *) mg_get_user_connection_data(conn);
+
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+    {
+        generate_response(conn, filename);
+        return false;
+    }
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    FILE *currFile = fopen(filename, "ab");
+    fwrite(data, sizeof(char), data_len, currFile);
+    fclose(currFile);
+
+    return true;
+}
+
+void PrsonaServerWebSocketHandler::generate_response(
+    struct mg_connection *conn,
+    char *filename)
+{
+    const struct mg_request_info *info = mg_get_request_info(conn);
+
+    switch (info->query_string[0])
+    {
+        case PRSONA_ADD_CLIENT:
+            add_new_client(conn, filename);
+            break;
+
+        case PRSONA_RECEIVE_VOTE:
+            receive_vote(filename);
+            break;
+
+        case PRSONA_GET_BGN_PUBKEY:
+            get_bgn_public_key(conn);
+            break;
+
+        case PRSONA_GET_NUM_CLIENTS:
+            get_num_clients(conn);
+            break;
+
+        case PRSONA_GET_NUM_SERVERS:
+            get_num_servers(conn);
+            break;
+
+        case PRSONA_GET_VOTES_BY:
+            get_current_votes_by(conn, filename);
+            break;
+
+        case PRSONA_GET_ALL_VOTES:
+            get_all_current_votes(conn);
+            break;
+
+        case PRSONA_GET_USER_TALLY:
+            get_current_user_encrypted_tally(conn, filename);
+            break;
+
+        case PRSONA_GET_SERVER_TALLY:
+            get_current_server_encrypted_tally(conn, filename);
+            break;
+
+        case PRSONA_GET_PSEUDONYMS:
+            get_current_pseudonyms(conn);
+            break;
+
+        case PRSONA_GET_VOTE_ROW_COMMITMENT:
+            get_vote_row_commitment(conn, filename);
+            break;
+
+        case PRSONA_GET_VOTE_MATRIX_COMMITMENT:
+            get_vote_matrix_commitment(conn);
+            break;
+
+        case PRSONA_GET_USER_TALLY_COMMITMENT:
+            get_user_tally_commitment(conn, filename);
+            break;
+
+        case PRSONA_GET_SERVER_TALLY_COMMITMENT:
+            get_server_tally_commitment(conn, filename);
+            break;
+
+        case PRSONA_GET_PSEUDONYMS_COMMITMENT:
+            get_pseudonyms_commitment(conn);
+            break;
+
+        case PRSONA_GET_BGN_DETAILS:
+            get_bgn_details(conn);
+            break;
+
+        case PRSONA_ADD_CURR_SEED_TO_GENERATOR:
+            add_seed_to_generator(conn, filename, true);
+            break;
+
+        case PRSONA_SET_FRESH_GENERATOR:
+            set_generator(filename, true);
+            break;
+
+        case PRSONA_ADD_RAND_SEED_TO_GENERATOR:
+            add_seed_to_generator(conn, filename, false);
+            break;
+
+        case PRSONA_SET_EG_BLIND_GENERATOR:
+            set_generator(filename, false);
+            break;
+
+        case PRSONA_EPOCH_BUILD_UP:
+            build_up_midway_pseudonyms(conn);
+            break;
+
+        case PRSONA_EPOCH_BREAK_DOWN:
+            break_down_midway_pseudonyms(conn);
+            break;
+
+        case PRSONA_EPOCH_UPDATE:
+            accept_epoch_updates(filename);
+            break;
+
+        case PRSONA_NEW_USER_UPDATE:
+            import_new_user_update(filename);
+            break;
+
+        case PRSONA_GET_PARTIAL_DECRYPTION:
+            get_partial_decryption(conn, filename);
+            break;
+
+        case PRSONA_RECEIVE_PARTIAL_DECRYPTION:
+            receive_tallied_scores(conn, filename);
+            break;
+
+        case PRSONA_GET_FRESH_GENERATOR:
+            get_generator(conn, true);
+            break;
+
+        case PRSONA_GET_EG_BLIND_GENERATOR:
+            get_generator(conn, false);
+            break;
+
+        default:
+            break;
+    }
+}
+
+virtual void PrsonaServerWebSocketHandler::handleClose(
+    CivetServer *server,
+    const struct mg_connection *conn)
+{
+    char *filename = (char *) mg_get_user_connection_data(conn);
+    if (!filename)
+        return;
+
+    remove(filename);
+    delete filename;
+}
+
+/*
+ * BASIC PUBLIC SYSTEM INFO GETTERS
+ */
+
+void PrsonaServerWebSocketHandler::get_bgn_public_key(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    BGNPublicKey pubKey = prsonaServer->get_bgn_public_key();
+    buffer << pubKey;
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_num_clients(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    size_t numClients = prsonaServer->get_num_clients();
+    buffer << numClients;
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_num_servers(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    size_t numServers = prsonaServer->get_num_servers();
+    buffer << numServers;
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+/*
+ * ENCRYPTED DATA GETTERS
+ */
+
+void PrsonaServerWebSocketHandler::get_current_votes_by(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi;
+    std::vector<TwistBipoint> votes =
+        prsonaServer->get_current_votes_by(pi, shortTermPublicKey);
+    
+    buffer << pi;
+    buffer << votes.size();
+    for (size_t i = 0; i < votes.size(); i++)
+        buffer << votes[i];
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_all_current_votes(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi;
+    std::vector<std::vector<TwistBipoint>> votes =
+        prsonaServer->get_all_current_votes(pi);
+    
+    buffer << pi;
+    buffer << votes.size();
+    for (size_t i = 0; i < votes.size(); i++)
+        for (size_t j = 0; j < votes[i].size(); j++)
+            buffer << votes[i][j];
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_current_user_encrypted_tally(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi;
+    EGCiphertext tally =
+        prsonaServer->get_current_user_encrypted_tally(pi, shortTermPublicKey);
+    
+    buffer << pi;
+    buffer << tally;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_current_server_encrypted_tally(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi;
+    CurveBipoint tally =
+        prsonaServer->get_current_server_encrypted_tally(pi, shortTermPublicKey);
+    
+    buffer << pi;
+    buffer << tally;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_current_pseudonyms(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi;
+    std::vector<Twistpoint> pseudonyms =
+        prsonaServer->get_current_pseudonyms(pi);
+    
+    buffer << pi;
+    buffer << pseudonyms.size();
+    for (size_t i = 0; i < pseudonyms.size(); i++)
+        buffer << pseudonyms[i];
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+/*
+ * PROOF COMMITMENT GETTERS
+ */
+
+void PrsonaServerWebSocketHandler::get_vote_row_commitment(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi =
+        prsonaServer->get_vote_row_commitment(shortTermPublicKey);
+    
+    buffer << pi;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_vote_matrix_commitment(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi =
+        prsonaServer->get_vote_matrix_commitment();
+    
+    buffer << pi;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_user_tally_commitment(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi =
+        prsonaServer->get_user_tally_commitment(shortTermPublicKey);
+    
+    buffer << pi;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_server_tally_commitment(
+    struct mg_connection *conn, const char *filename) const
+{
+    ifstream file(filename);
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi =
+        prsonaServer->get_server_tally_commitment(shortTermPublicKey);
+    
+    buffer << pi;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::get_pseudonyms_commitment(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    Proof pi =
+        prsonaServer->get_pseudonyms_commitment();
+    
+    buffer << pi;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::distribute_new_user_updates(
+    std::vector<Proof> proofOfValidAddition,
+    std::vector<CurveBipoint> previousVoteTallies,
+    std::vector<Twistpoint> currentPseudonyms,
+    std::vector<EGCiphertext> currentUserEncryptedTallies,
+    std::vector<std::vector<TwistBipoint>> voteMatrix) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    buffer << proofOfValidAddition.size();
+    for (size_t i = 0; i < proofOfValidAddition.size(); i++)
+        buffer << proofOfValidAddition[i];
+
+    buffer << previousVoteTallies.size();
+    for (size_t i = 0; i < previousVoteTallies.size(); i++)
+        buffer << previousVoteTallies[i];
+
+    buffer << currentPseudonyms.size();
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+        buffer << currentPseudonyms[i];
+
+    buffer << currentUserEncryptedTallies.size();
+    for (size_t i = 0; i < currentUserEncryptedTallies.size(); i++)
+        buffer << currentUserEncryptedTallies[i];
+
+    buffer << voteMatrix.size();
+    for (size_t i = 0; i < voteMatrix.size(); i++)
+        for (size_t j = 0; j < voteMatrix[i].size(); j++)
+        buffer << voteMatrix[i][j];
+
+    data = buffer.str();
+
+    size_t i = 0;
+    while (i < serverIPs.size())
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                GIVE_NEW_USER_URI,
+                "null",
+                synchro_websocket_data_handler,
+                synchro_websocket_close_handler,
+                (void *) distributeSynch);
+
+        if (!conn)
+        {
+            std::cerr << "Couldn't give server " << i << " new user" << std::endl;
+            continue;
+        }
+
+        unique_lock<mutex> synchLock(distributeSynch->mtx);
+        distributeSynch->isReady = false;
+        distributeSynch->isOngoing = true;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        while (distributeSynch->isOngoing)
+            distributeSynch->cv.wait(synchLock);
+
+        if (distributeSynch->isReady)
+            i++;
+    }
+}
+
+void PrsonaServerWebSocketHandler::distribute_new_vote(
+    std::vector<Proof> pi;
+    std::vector<TwistBipoint> newVotes,
+    Twistpoint shortTermPublicKey) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    buffer << pi.size();
+    for (size_t i = 0; i < pi.size(); i++)
+        buffer << pi[i];
+
+    buffer << newVotes.size();
+    for (size_t i = 0; i < newVotes.size(); i++)
+        buffer << newVotes[i];
+
+    buffer << shortTermPublicKey;
+    buffer << false;
+
+    data = buffer.str();
+
+    size_t i = 0;
+    while (i < serverIPs.size())
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                GIVE_NEW_VOTE_URI,
+                "null",
+                synchro_websocket_data_handler,
+                synchro_websocket_close_handler,
+                (void *) distributeSynch);
+
+        if (!conn)
+        {
+            std::cerr << "Couldn't give server " << i << " new user" << std::endl;
+            continue;
+        }
+
+        unique_lock<mutex> synchLock(distributeSynch->mtx);
+        distributeSynch->isReady = false;
+        distributeSynch->isOngoing = true;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        while (distributeSynch->isOngoing)
+            distributeSynch->cv.wait(synchLock);
+
+        if (distributeSynch->isReady)
+            i++;
+    }
+}
+
+/*
+ * CLIENT INTERACTIONS
+ */
+
+void PrsonaServerWebSocketHandler::add_new_client(
+    struct mg_connection *conn, const char *filename)
+{
+    ifstream file(filename);
+
+    Proof proofOfValidKey;
+    file >> proofOfValidKey;
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    std::unique_lock<std::mutex> lck(*updateMtx, std::defer_lock);
+    obtain_update_locks(
+        lck,
+        serverIPs,
+        selfIP,
+        &updateSynch);
+
+    std::vector<Proof> proofOfValidAddition;
+    prsonaServer->add_new_client(
+        proofOfValidAddition,
+        proofOfValidKey,
+        shortTermPublicKey);
+
+    std::vector<CurveBipoint> previousVoteTallies;
+    std::vector<Twistpoint> currentPseudonyms;
+    std::vector<EGCiphertext> currentUserEncryptedTallies;
+    std::vector<std::vector<TwistBipoint>> voteMatrix;
+    prsonaServer->export_new_user_update(
+        previousVoteTallies,
+        currentPseudonyms,
+        currentUserEncryptedTallies,
+        voteMatrix);
+
+    distribute_new_user_updates(
+        proofOfValidAddition,
+        previousVoteTallies,
+        currentPseudonyms,
+        currentUserEncryptedTallies,
+        voteMatrix);
+
+    release_update_locks(
+        lck,
+        serverIPs,
+        selfIP,
+        &updateSynch);
+
+    buffer << proofOfValidAddition.size();
+    for (size_t i = 0; i < proofOfValidAddition.size(); i++)
+        buffer << proofOfValidAddition[i];
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::receive_vote(
+    const char *filename)
+{
+    ifstream file(filename);
+
+    size_t sizeOfPi;
+    file >> sizeOfPi;
+
+    std::vector<Proof> pi;
+    for (size_t i = 0; i < sizeOfPi; i++)
+    {
+        Proof currProof;
+        file >> currProof;
+
+        pi.push_back(currProof);
+    }
+
+    size_t sizeOfVotes;
+    file >> sizeOfVotes;
+
+    std::vector<TwistBipoint> newVotes;
+    for (size_t i = 0; i < sizeOfVotes; i++)
+    {
+        TwistBipoint currVote;
+        file >> currVote;
+
+        newVotes.push_back(currVote);
+    }
+
+    Twistpoint shortTermPublicKey;
+    file >> shortTermPublicKey;
+
+    bool shouldDeal;
+    file >> shouldDeal;
+
+    std::unique_lock<std::mutex> lck(*updateMtx, std::defer_lock);
+    if (shouldDeal)
+    {
+        obtain_update_locks(
+            lck,
+            serverIPs,
+            selfIP,
+            &distributeSynch);
+    }
+
+    prsonaServer->receive_vote(
+        pi,
+        newVotes,
+        shortTermPublicKey);
+
+    if (shouldDeal)
+    {
+        distribute_new_vote(pi, newVotes, shortTermPublicKey);
+        release_update_locks(
+            lck,
+            serverIPs,
+            selfIP,
+            &distributeSynch);
+    }
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+/*
+ * CONSTRUCTOR HELPERS
+ */
+
+void PrsonaServerWebSocketHandler::get_bgn_details(
+    struct mg_connection *conn) const
+{
+    std::stringstream buffer;
+    std::string data;
+
+    const BGN& sharedBGN = prsonaServer->get_bgn_details();
+    buffer << sharedBGN;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::add_seed_to_generator(
+    struct mg_connection *conn, const char *filename, bool fresh) const
+{
+    ifstream file(filename);
+
+    Twistpoint currGenerator;
+    file >> currGenerator;
+
+    std::stringstream buffer;
+    std::string data;
+
+    std::vector<Proof> pi;
+    if (fresh)
+    {
+        currGenerator =
+            prsonaServer->add_curr_seed_to_generator(pi, currGenerator);
+    }
+    else
+    {
+        currGenerator =
+            prsonaServer->add_rand_seed_to_generator(pi, currGenerator);
+    }
+    
+    buffer << pi[0];
+    buffer << currGenerator;
+
+    data = buffer.str();
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+}
+
+void PrsonaServerWebSocketHandler::set_generator(
+    const char *filename, bool fresh)
+{
+    ifstream file(filename);
+
+    size_t sizeOfPi;
+    file >> sizeOfPi;
+
+    std::vector<Proof> pi;
+    for (size_t i = 0; i < sizeOfPi; i++)
+    {
+        Proof currProof;
+        file >> currProof;
+        pi.push_back(currProof);
+    }
+
+    Twistpoint newGenerator;
+    file >> newGenerator;
+
+    if (fresh)
+        prsonaServer->initialize_fresh_generator(pi, newGenerator);
+    else
+        prsonaServer->set_EG_blind_generator(pi, newGenerator);
+}
+
+/*
+ * EPOCH ROUNDS
+ */
+
+void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
+    struct mg_connection *conn, const char *filename)
+{
+    std::vector<std::vector<Proof>> generatorProofHolder;
+    std::vector<Proof> generatorProof;
+    Twistpoint nextGenerator;
+
+    read_epoch_initiator_string(
+        filename,
+        generatorProof,
+        nextGenerator);
+
+    generatorProofHolder.push_back(generatorProof);
+
+    std::vector<std::vector<std::vector<Proof>>> pi;
+    std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymSeedCommits;
+    std::vector<std::vector<std::vector<CurveBipoint>>> serverTallyCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> partwayVoteMatrixCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> finalVoteMatrixCommits;
+
+    pi.push_back(generatorProofHolder);
+
+    prsonaServer->build_up_midway_pseudonyms(
+        pi,
+        permutationCommits,
+        freshPseudonymCommits,
+        freshPseudonymSeedCommits,
+        serverTallyCommits,
+        partwayVoteMatrixCommits,
+        finalVoteMatrixCommits,
+        nextGenerator);
+
+    std::vector<std::vector<Twistpoint>> userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits;
+
+    string data =
+        make_epoch_update_string(
+            pi[1],
+            permutationCommits[0],
+            freshPseudonymCommits[0],
+            freshPseudonymSeedCommits[0],
+            serverTallyCommits[0],
+            partwayVoteMatrixCommits[0],
+            finalVoteMatrixCommits[0],
+            userTallyMaskCommits,
+            userTallyMessageCommits,
+            userTallySeedCommits,
+            nextGenerator,
+            false);
+
+    struct synchronization_tool epochSync;
+    epochSync->val = 1;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        distribute_epoch_updates(
+            serverIPs[i],
+            data,
+            &epochSync);
+    }
+
+    unique_lock<mutex> lck(epochSync);
+    while (epochSync.val < serverIPs.size())
+        epochSync.cv.wait(lck);
+    
+    data = make_epoch_initiator_string(
+        pi[0][0],
+        nextGenerator);
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
+    struct mg_connection *conn, const char *filename)
+{
+    std::vector<Proof> generatorProof;
+    Twistpoint nextGenerator;
+
+    read_epoch_initiator_string(
+        filename,
+        generatorProof,
+        nextGenerator);
+
+    std::vector<std::vector<std::vector<Proof>>> pi;
+    std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymSeedCommits;
+    std::vector<std::vector<std::vector<CurveBipoint>>> serverTallyCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> partwayVoteMatrixCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> finalVoteMatrixCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallyMaskCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallyMessageCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallySeedCommits;
+
+    prsonaServer->break_down_midway_pseudonyms(
+        generatorProof,
+        pi,
+        permutationCommits,
+        freshPseudonymCommits,
+        freshPseudonymSeedCommits,
+        serverTallyCommits,
+        partwayVoteMatrixCommits,
+        finalVoteMatrixCommits,
+        userTallyMaskCommits,
+        userTallyMessageCommits,
+        userTallySeedCommits,
+        nextGenerator);
+
+    string data =
+        make_epoch_update_string(
+            pi[0],
+            permutationCommits[0],
+            freshPseudonymCommits[0],
+            freshPseudonymSeedCommits[0],
+            serverTallyCommits[0],
+            partwayVoteMatrixCommits[0],
+            finalVoteMatrixCommits[0],
+            userTallyMaskCommits[0],
+            userTallyMessageCommits[0],
+            userTallySeedCommits[0],
+            nextGenerator,
+            true);
+
+    struct synchronization_tool epochSync;
+    epochSync.val = 1;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        distribute_epoch_updates(
+            serverIPs[i],
+            data,
+            &epochSync);
+    }
+
+    unique_lock<mutex> lck(epochSync.mtx);
+    while (epochSync.val < serverIPs.size())
+        epochSync.cv.wait(lck);
+
+    (*epochNum)++;
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+void PrsonaServerWebSocketHandler::accept_epoch_updates(
+    struct mg_connection *conn, const char *filename)
+{
+    std::vector<std::vector<Proof>> pi;
+    std::vector<std::vector<Twistpoint>> permutationCommits;
+    std::vector<std::vector<Twistpoint>> freshPseudonymCommits;
+    std::vector<std::vector<Twistpoint>> freshPseudonymSeedCommits;
+    std::vector<std::vector<CurveBipoint>> serverTallyCommits;
+    std::vector<std::vector<std::vector<TwistBipoint>>> partwayVoteMatrixCommits;
+    std::vector<std::vector<std::vector<TwistBipoint>>> finalVoteMatrixCommits;
+    std::vector<std::vector<Twistpoint>> userTallyMaskCommits;
+    std::vector<std::vector<Twistpoint>> userTallyMessageCommits;
+    std::vector<std::vector<Twistpoint>> userTallySeedCommits;
+    Twistpoint nextGenerator;
+    bool doUserTallies =
+        read_epoch_update_string(
+            filename,
+            pi,
+            permutationCommits,
+            freshPseudonymCommits,
+            freshPseudonymSeedCommits,
+            serverTallyCommits,
+            partwayVoteMatrixCommits,
+            finalVoteMatrixCommits,
+            userTallyMaskCommits,
+            userTallyMessageCommits,
+            userTallySeedCommits,
+            nextGenerator);
+
+    prsonaServer->accept_epoch_updates(
+        pi,
+        permutationCommits,
+        freshPseudonymCommits,
+        freshPseudonymSeedCommits,
+        serverTallyCommits,
+        partwayVoteMatrixCommits,
+        finalVoteMatrixCommits,
+        userTallyMaskCommits,
+        userTallyMessageCommits,
+        userTallySeedCommits,
+        nextGenerator,
+        doUserTallies);
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+/*
+ * DATA MAINTENANCE
+ */
+
+void PrsonaServerWebSocketHandler::import_new_user_update(
+    const char *filename)
+{
+    std::vector<Proof> proofOfValidAddition;
+    std::vector<CurveBipoint> previousVoteTallies;
+    std::vector<Twistpoint> currentPseudonyms;
+    std::vector<EGCiphertext> currentUserEncryptedTallies;
+    std::vector<std::vector<TwistBipoint>> voteMatrix;
+
+    ifstream file(filename);
+
+    buffer << voteMatrix.size();
+    for (size_t i = 0; i < voteMatrix.size(); i++)
+        for (size_t j = 0; j < voteMatrix[i].size(); j++)
+        buffer << voteMatrix[i][j];
+
+    size_t sizeOfVector;
+    
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        Proof currProof;
+        file >> currProof;
+        proofOfValidAddition.push_back(currProof);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        CurveBipoint currTally;
+        file >> currTally;
+        previousVoteTallies.push_back(currTally);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        Twistpoint currNym;
+        file >> currNym;
+        currentPseudonyms.push_back(currNym);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        EGCiphertext currTally;
+        file >> currTally;
+        currentUserEncryptedTallies.push_back(currTally);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        std::vector<TwistBipoint> currRow;
+        for (size_t j = 0; j < sizeOfVector; j++)
+        {
+            TwistBipoint currVote;
+            file >> currVote;
+            currRow.push_back(currVote);
+        }
+        voteMatrix.push_back(currRow);
+    }
+
+    prsonaServer->import_new_user_update(
+        proofOfValidAddition,
+        previousVoteTallies,
+        currentPseudonyms,
+        currentUserEncryptedTallies,
+        voteMatrix);
+}
+
+void PrsonaServerWebSocketHandler::get_partial_decryption(
+    struct mg_connection *conn)
+{
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+void PrsonaServerWebSocketHandler::receive_tallied_scores(
+    struct mg_connection *conn, const char *filename)
+{
+    ifstream file(filename);
+
+    std::vector<EGCiphertext> userScores;
+    std::vector<CurveBipoint> serverScores;
+
+    size_t sizeOfVector;
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        EGCiphertext currScore;
+        file >> currScore;
+        userScores.push_back(currScore);
+    }
+
+    for (size_t i = 0; i < sizeOfVector; i++)
+    {
+        CurveBipoint currScore;
+        file >> currScore;
+        serverScores.push_back(currScore);
+    }
+
+    prsonaServer->receive_tallied_scores(userScores, serverScores);
+
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
+void PrsonaServerWebSocketHandler::get_generator(
+    struct mg_connection *conn, bool fresh)
+{
+    Twistpoint generator;
+    std::vector<Proof> pi;
+    if (fresh)
+        generator = prsonaServer->get_fresh_generator(pi);
+    else
+        generator = prsonaServer->get_blinding_generator(pi);
+
+    std::stringstream buffer;
+    std::string data;
+
+    buffer << pi.size();
+    for (size_t i = 0; i < pi.size(); i++)
+        buffer << pi[i];
+
+    buffer << generator;
+
+    data = buffer.str();
 
-// Used for all other servers, so they have the same BGN parameters
-PrsonaNetworkServer::PrsonaNetworkServer(size_t numServers, const BGN& otherBgn)
-: PrsonaServer(numServers, otherBgn)
-{ /* Do nothing */ }
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}

+ 1141 - 0
prsona/src/serverMain.cpp

@@ -0,0 +1,1141 @@
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <cstdlib>
+#include <vector>
+#include <string>
+
+#include "networkServer.hpp"
+
+#define EXIT_URI "/exit"
+#define BEGIN_URI "/begin"
+#define READY_URI "/ready"
+#define EPOCH_URI "/epoch"
+#define BGN_URI "/ws?p"
+#define GET_FRESH_GEN_URI "/ws?q"
+#define GIVE_FRESH_GEN_URI "/ws?r"
+#define GET_BLIND_GEN_URI "/ws?s"
+#define GIVE_BLIND_GEN_URI "/ws?t"
+#define EPOCH_BUILD_UP_URI "/ws?u"
+#define EPOCH_BREAK_DOWN_URI "/ws?v"
+#define GIVE_BLIND_GEN_URI "/ws?t"
+#define GET_DECRYPTION_URI "/ws?y"
+#define GIVE_DECRYPTION_URI "/ws?z"
+#define BGN_TMP_FILE "~/tmp/bgn"
+#define GEN_TMP_FILE "~/tmp/generator"
+#define EPOCH_GEN_TMP_FILE "~/tmp/epoch"
+
+using namespace std;
+
+struct synchronization_tool exitSync, bgnSync, generatorSync, readySync, updateSync, epochSync, tallySync;
+mutex updateMtx;
+
+size_t epochNum = 0;
+
+// Initialize the classes we use
+void initialize_prsona_classes()
+{
+    Scalar::init();
+    PrsonaBase::init();
+    PrsonaBase::set_client_malicious();
+}
+
+PrsonaServer *create_server_from_bgn_file(size_t numServers)
+{
+    unique_lock<mutex> lck(bgnSync.mtx);
+    ifstream bgnFile(BGN_TMP_FILE);
+    BGN privateKey;
+    bgnFile >> privateKey;
+
+    return new PrsonaServer(numServers, privateKey);
+}
+
+static int bgn_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE)
+        return false;
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    unique_lock<mutex> lck(bgnSync.mtx);
+    FILE *currFile = fopen(BGN_TMP_FILE, "ab");
+    fwrite(data, sizeof(char), data_len, currFile);
+    fclose(currFile);
+
+    return true;
+}
+
+static void bgn_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data)
+{
+    unique_lock<mutex> lck(bgnSync.mtx);
+    bgnSync.val = 1;
+    bgnSync.cv.notify_all();
+}
+
+Twistpoint update_generator_from_gen_file(Proof& pi)
+{
+    unique_lock<mutex> lck(generatorSync.mtx);
+    ifstream genFile(GEN_TMP_FILE);
+    Twistpoint retval;
+
+    genFile >> pi;
+    genFile >> retval;
+
+    return retval;
+}
+
+Twistpoint update_data_from_epoch_gen_file(vector<Proof>& pi)
+{
+    unique_lock<mutex> lck(epochSync.mtx);
+    ifstream epochFile(EPOCH_GEN_TMP_FILE);
+    
+    Twistpoint retval;
+    size_t piSize;
+    pi.clear();
+
+    epochFile >> piSize;
+    for (size_t i = 0; i < piSize; i++)
+    {
+        Proof currProof;
+        epochFile >> currProof;
+        pi.push_back(currProof);
+    }
+    epochFile >> retval;
+
+    return retval;
+}
+
+static int generator_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{
+    struct synchronization_tool *synch = (struct synchronization_tool *) user_data;
+
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE || (bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+        return false;
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    unique_lock<mutex> lck(generatorSync.mtx);
+    FILE *currFile = fopen(GEN_TMP_FILE, "ab");
+    fwrite(data, sizeof(char), data_len, currFile);
+    fclose(currFile);
+
+    return true;
+}
+
+static void generator_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data)
+{
+    unique_lock<mutex> lck(generatorSync.mtx);
+    generatorSync.val = 1;
+    generatorSync.cv.notify_all();
+}
+
+static int epoch_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE)
+        return false
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+    {
+        unique_lock<mutex> lck(epochSync.mtx);
+        epochSync.val++;
+
+        return false;
+    }
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    unique_lock<mutex> lck(epochSync.mtx);
+    FILE *currFile = fopen(EPOCH_GEN_TMP_FILE, "ab");
+    fwrite(data, sizeof(char), data_len, currFile);
+    fclose(currFile);
+
+    return true;
+}
+
+static void epoch_websocket_close_handler(
+    const struct mg_connection *conn,
+    void *user_data)
+{
+    unique_lock<mutex> lck(epochSync.mtx);
+    epochSync.val2 = 0;
+    epochSync.cv.notify_all();
+}
+
+static int tally_websocket_data_handler(
+    struct mg_connection *conn,
+    int bits,
+    char *data,
+    size_t data_len,
+    void *user_data)
+{
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE)
+        return false;
+
+    if ((bits & 0xf) == MG_WEBSOCKET_OPCODE_DATACOMPLETE)
+    {
+        unique_lock<mutex> lck(tallySync.mtx);
+        tallySync.val++;
+
+        tallySync.cv.notify_all();
+
+        return false;
+    }
+
+    if ((bits & 0xf) != MG_WEBSOCKET_OPCODE_BINARY && (bits & 0xf) != MG_WEBSOCKET_OPCODE_CONTINUATION)
+    {
+        std::cerr << "Unknown opcode: failing." << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+Twistpoint get_generator(
+    vector<Proof>& pi,
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP,
+    bool fresh)
+{
+    Twistpoint retval = PrsonaServer::EL_GAMAL_GENERATOR;
+    pi.clear();
+
+    if (fresh)
+        retval = prsonaServer->add_curr_seed_to_generator(pi, retval);
+    else
+        retval = prsonaServer->add_rand_seed_to_generator(pi, retval);
+
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        char* which;
+        if (fresh)
+            which = GET_FRESH_GEN_URI;
+        else
+            which = GET_BLIND_GEN_URI;
+
+        Proof currProof;
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                which,
+                "null",
+                generator_websocket_data_handler,
+                generator_websocket_close_handler,
+                NULL);
+
+        if (!conn)
+        {
+            cerr << "Couldn't get server " << i << "'s update on generator" << endl;
+            return 1;
+        }
+
+        stringstream buffer;
+        string data;
+        buffer << retval;
+        data = buffer.str();
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        unique_lock<mutex> lck(generatorSync.mtx);
+        remove(GEN_TMP_FILE);
+        generatorSync.val = 0;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        while (!generatorSync.val)
+            generatorSync.cv.wait(lck);
+
+        retval = update_generator_from_gen_file(currProof);
+        pi.push_back(currProof);
+    }
+
+    return retval;
+}
+
+void handout_generator(
+    const vector<Proof>& pi,
+    const Twistpoint generator,
+    PrsonaServer *prsonaServer,
+    const vector<string> serverIPs,
+    string selfIP,
+    bool fresh)
+{
+    if (fresh)
+        prsonaServer->initialize_fresh_generator(pi, generator);
+    else
+        prsonaServer->set_EG_blind_generator(pi, generator);
+
+    stringstream buffer;
+    string data;
+    
+    buffer << pi.size();
+    for (size_t i = 0; i < pi.size(); i++)
+        buffer << pi[i];
+
+    buffer << generator;
+    data = buffer.str();
+
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+            continue;
+
+        char* which;
+        if (fresh)
+            which = GIVE_FRESH_GEN_URI;
+        else
+            which = GIVE_BLIND_GEN_URI;
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                which,
+                "null",
+                empty_websocket_data_handler,
+                empty_websocket_close_handler,
+                NULL);
+
+        if (!conn)
+        {
+            cerr << "Couldn't give " << (fresh ? "fresh" : "blind") << " generator to server " << i << endl;
+            return 1;
+        }
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+    }
+}
+
+Twistpoint initiate_epoch_updates(
+    const string& recipient,
+    const string& data,
+    vector<vector<Proof>>& generatorProofHolder,
+    bool isBreakdown)
+{
+    Twistpoint retval;
+    struct synchronization_tool epochSync;
+
+    bool flag = false;
+    while (!flag)
+    {
+        char* which;
+        if (isBreakdown)
+            which = EPOCH_BREAK_DOWN_URI;
+        else
+            which = EPOCH_BUILD_UP_URI;
+
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                serverIPs[i].c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                which,
+                "null",
+                epoch_websocket_data_handler,
+                epoch_websocket_close_handler,
+                NULL);
+
+        if (!conn)
+        {
+            std::cerr << "Trouble initiating epoch update with server at " << recipient << std::endl;
+            continue;
+        }
+        
+        unique_lock<mutex> lck(epochSync.mtx);
+        remove(EPOCH_GEN_TMP_FILE);
+        epochSync.val = 0;
+        epochSync.val2 = 1;
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_BINARY,
+            data.c_str(),
+            data.length());
+
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        while (epochSync.val2)
+            epochSync.cv.wait(lck);
+
+        if (!epochSync.val)
+            flag = true;
+    }
+
+    if (isBreakdown)
+        return retval;
+
+    vector<Proof> generatorProof;
+    generatorProofHolder.clear();
+
+    retval = update_data_from_epoch_gen_file(generatorProof);
+
+    generatorProofHolder.push_back(generatorProof);
+
+
+
+    return retval;
+}
+
+vector<Proof> epoch_build_up(
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP,
+    Twistpoint& nextGenerator)
+{
+    std::vector<std::vector<std::vector<Proof>>> pi;
+    std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymSeedCommits;
+    std::vector<std::vector<std::vector<CurveBipoint>>> serverTallyCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> partwayVoteMatrixCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> finalVoteMatrixCommits;
+
+    std::vector<std::vector<Proof>> generatorProofHolder(1);
+
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+        {
+            pi.clear();
+            permutationCommits.clear();
+            freshPseudonymCommits.clear();
+            freshPseudonymSeedCommits.clear();
+            serverTallyCommits.clear();
+            partwayVoteMatrixCommits.clear();
+            finalVoteMatrixCommits.clear();
+
+            pi.push_back(generatorProofHolder);
+
+            prsonaServer->build_up_midway_pseudonyms(
+                pi,
+                permutationCommits,
+                freshPseudonymCommits,
+                freshPseudonymSeedCommits,
+                serverTallyCommits,
+                partwayVoteMatrixCommits,
+                finalVoteMatrixCommits,
+                nextGenerator);
+
+            vector<vector<Twistpoint>> currUserTallyMaskCommits;
+            vector<vector<Twistpoint>> currUserTallyMessageCommits;
+            vector<vector<Twistpoint>> currUserTallySeedCommits;
+
+            string data = make_epoch_update_string(
+                pi[1],
+                permutationCommits[0],
+                freshPseudonymCommits[0],
+                freshPseudonymSeedCommits[0],
+                serverTallyCommits[0],
+                partwayVoteMatrixCommits[0],
+                finalVoteMatrixCommits[0],
+                nextGenerator[0],
+                currUserTallyMaskCommits,
+                currUserTallyMessageCommits,
+                currUserTallySeedCommits,
+                nextGenerator,
+                false);
+
+            struct synchronization_tool epochSync;
+            epochSync->val = 1;
+            for (size_t j = 0; j < serverIPs.size(); j++)
+            {
+                if (i == j)
+                    continue;
+
+                distribute_epoch_updates(
+                    serverIPs[j],
+                    data,
+                    &epochSync);
+            }
+            unique_lock<mutex> lck(epochSync);
+            while (epochSync.val < serverIPs.size())
+                epochSync.cv.wait(lck);
+
+            generatorProofHolder = pi[0];
+        }
+        else
+        {
+            string data = make_epoch_initiator_string(
+                generatorProofHolder[0],
+                nextGenerator);
+            nextGenerator = initiate_epoch_updates(
+                serverIPs[j],
+                data,
+                generatorProofHolder,
+                false);
+        }
+    }
+
+    return generatorProofHolder[0];
+}
+
+void epoch_break_down(
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP,
+    const vector<Proof>& generatorProof,
+    const Twistpoint& nextGenerator)
+{
+    std::vector<std::vector<std::vector<Proof>>> pi;
+    std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> freshPseudonymSeedCommits;
+    std::vector<std::vector<std::vector<CurveBipoint>>> serverTallyCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> partwayVoteMatrixCommits;
+    std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> finalVoteMatrixCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallyMaskCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallyMessageCommits;
+    std::vector<std::vector<std::vector<Twistpoint>>> userTallySeedCommits;
+
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        pi.clear();
+        permutationCommits.clear();
+        freshPseudonymCommits.clear();
+        freshPseudonymSeedCommits.clear();
+        serverTallyCommits.clear();
+        partwayVoteMatrixCommits.clear();
+        finalVoteMatrixCommits.clear();
+        userTallyMaskCommits.clear();
+        userTallyMessageCommits.clear();
+        userTallySeedCommits.clear();
+
+        if (serverIPs[i] == selfIP)
+        {
+            prsonaServer->break_down_midway_pseudonyms(
+                generatorProof,
+                pi,
+                permutationCommits,
+                freshPseudonymCommits,
+                freshPseudonymSeedCommits,
+                serverTallyCommits,
+                partwayVoteMatrixCommits,
+                finalVoteMatrixCommits,
+                userTallyMaskCommits,
+                userTallyMessageCommits,
+                userTallySeedCommits,
+                nextGenerator);
+
+            string data = make_epoch_update_string(
+                pi[0],
+                permutationCommits[0],
+                freshPseudonymCommits[0],
+                freshPseudonymSeedCommits[0],
+                serverTallyCommits[0],
+                partwayVoteMatrixCommits[0],
+                finalVoteMatrixCommits[0],
+                nextGenerator[0],
+                userTallyMaskCommits[0],
+                userTallyMessageCommits[0],
+                userTallySeedCommits[0],
+                nextGenerator,
+                true);
+
+            struct synchronization_tool epochSync;
+            epochSync->val = 1;
+            for (size_t j = 0; j < serverIPs.size(); j++)
+            {
+                if (i == j)
+                    continue;
+
+                distribute_epoch_updates(
+                    serverIPs[j],
+                    data,
+                    &epochSync);
+            }
+            unique_lock<mutex> lck(epochSync.mtx);
+            while (epochSync.val < serverIPs.size())
+                epochSync.cv.wait(lck);
+
+            epochNum++;
+        }
+        else
+        {
+            vector<vector<Proof>> unused;
+            string data = make_epoch_initiator_string(
+                generatorProof,
+                nextGenerator);
+            initiate_epoch_updates(
+                serverIPs[j],
+                data,
+                unused,
+                true);
+        }
+    }
+}
+
+void tally_scores(
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP,
+    const Twistpoint& nextGenerator,
+    std::vector<EGCiphertext>& userTallyScores,
+    std::vector<CurveBipoint>& serverTallyScores)
+{
+    tallySync.val = 0;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+        {
+            unique_lock<mutex> lck(tallySync.mtx);
+            tallySync.val++;
+            continue;
+        }
+        else
+        {
+            bool flag = false;
+            while (!flag)
+            {
+                struct mg_connection *conn =
+                    mg_connect_websocket_client(
+                        serverIPs[i].c_str(),
+                        PRSONA_PORT,
+                        USE_SSL,
+                        NULL,
+                        0,
+                        GET_DECRYPTION_URI,
+                        "null",
+                        tally_websocket_data_handler,
+                        empty_websocket_close_handler,
+                        NULL);
+
+                if (!conn)
+                {
+                    std::cerr << "Trouble initiating epoch update with server at " << recipient << std::endl;
+                    continue;
+                }
+
+                mg_websocket_client_write(
+                    conn,
+                    MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+                    "",
+                    0);
+            }
+        }
+    }
+
+    unique_lock<mutex> lck(tallySync.mtx)
+    while (tallySync.val < serverIPs.size())
+        tallySync.cv.wait(lck);
+
+    std::vector<EGCiphertext> retval;
+    std::vector<Scalar> decryptedTalliedScores = prsonaServer->tally_scores();
+    mpz_class maxScorePossibleThisRound =
+        prsonaServer->get_max_possible_score().toInt() *
+        PrsonaBase::get_max_allowed_vote();
+    mpz_class topOfScoreRange =
+        decryptedTalliedScores.size() * PrsonaBase::get_max_allowed_vote();
+
+    userTallyScores.clear();
+    serverTallyScores.clear();
+    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
+    {
+        decryptedTalliedScores[i] =
+            Scalar(
+                (decryptedTalliedScores[i].toInt() * topOfScoreRange) /
+                maxScorePossibleThisRound
+            );
+
+        EGCiphertext currCiphertext;
+        userTallyScores.push_back(currCiphertext);
+        CurveBipoint currServerScore;
+        serverTallyScores.push_back(currServerScore);
+        Scalar currMask;
+        currMask.set_random();
+
+        // Give the server the new weights,
+        // to get passed around to the other servers
+        prsonaServer->bgnSystem.encrypt(
+            serverTallyScores[i], decryptedTalliedScores[i]);
+
+        userTallyScores[i].mask = prsonaServer->currentPseudonyms[i] * currMask;
+        userTallyScores[i].encryptedMessage =
+            (nextGenerator * currMask) +
+            (prsonaServer->get_blinding_generator() * decryptedTalliedScores[i]);
+    }
+}
+
+void distribute_tallied_scores(
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP,
+    const Twistpoint& nextGenerator,
+    const std::vector<EGCiphertext>& userTallyScores,
+    const std::vector<CurveBipoint>& serverTallyScores)
+{
+    stringstream buffer;
+    string data;
+    
+    buffer << userTallyScores.size();
+    for (size_t i = 0; i < userTallyScores.size(); i++)
+        buffer << userTallyScores[i];
+    for (size_t i = 0; i < serverTallyScores.size(); i++)
+        buffer << serverTallyScores[i];
+
+    data = buffer.str();
+
+    tallySync.val = 0;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP)
+        {
+            prsonaServer->receive_tallied_scores(userTallyScores, serverTallyScores);
+            unique_lock<mutex> lck(tallySync.mtx);
+            tallySync.val++;
+            continue;
+        }
+        else
+        {
+            bool flag = false;
+            while (!flag)
+            {
+                struct mg_connection *conn =
+                    mg_connect_websocket_client(
+                        serverIPs[i].c_str(),
+                        PRSONA_PORT,
+                        USE_SSL,
+                        NULL,
+                        0,
+                        GIVE_DECRYPTION_URI,
+                        "null",
+                        tally_websocket_data_handler,
+                        empty_websocket_close_handler,
+                        NULL);
+
+                if (!conn)
+                {
+                    std::cerr << "Trouble initiating epoch update with server at " << recipient << std::endl;
+                    continue;
+                }
+
+                mg_websocket_client_write(
+                    conn,
+                    MG_WEBSOCKET_OPCODE_BINARY,
+                    data.c_str(),
+                    data.length());
+
+                mg_websocket_client_write(
+                    conn,
+                    MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+                    "",
+                    0);
+            }
+        }
+    }
+
+    unique_lock<mutex> lck(tallySync.mtx)
+    while (tallySync.val < serverIPs.size())
+        tallySync.cv.wait(lck);
+}
+
+void epoch(
+    PrsonaServer *prsonaServer,
+    const vector<string>& serverIPs,
+    const string& selfIP)
+{
+    Twistpoint nextGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
+    
+    unique_lock<mutex> lck(updateMtx, defer_lock);
+    obtain_update_locks(
+        lck,
+        serverIPs,
+        selfIP,
+        updateSync);
+
+    vector<Proof> generatorProof =
+        epoch_build_up(
+            prsonaServer,
+            serverIPs,
+            selfIP,
+            nextGenerator);
+
+    std::vector<EGCiphertext> currentUserEncryptedTallies;
+    std::vector<CurveBipoint> currentServerEncryptedTallies;
+
+    tally_scores(
+        prsonaServer,
+        serverIPs,
+        selfIP,
+        nextGenerator,
+        currentUserEncryptedTallies,
+        currentServerEncryptedTallies);
+
+    distribute_tallied_scores(
+        prsonaServer,
+        serverIPs,
+        selfIP,
+        nextGenerator,
+        currentUserEncryptedTallies,
+        currentServerEncryptedTallies);
+
+    epoch_break_down(
+        prsonaServer,
+        serverIPs,
+        selfIP,
+        generatorProof,
+        nextGenerator);
+
+    release_update_locks(
+        lck,
+        serverIPs,
+        selfIP,
+        updateSync);
+}
+
+class ExitHandler : public CivetHandler
+{
+    public:
+        bool handleGet(CivetServer *server, struct mg_connection *conn)
+        {
+            unique_lock<mutex> lck(exitSync.mtx);
+
+            mg_printf(conn,
+                      "HTTP/1.1 200 OK\r\nContent-Type: "
+                      "text/plain\r\nConnection: close\r\n\r\n");
+            mg_printf(conn, "Server coming down!\n");
+
+            exitSync.val = 1;
+            exitSync.cv.notify_all();
+
+            return true;
+        }
+};
+
+class BeginHandler : public CivetHandler
+{
+    public:
+        bool handleGet(CivetServer *server, struct mg_connection *conn)
+        {
+            unique_lock<mutex> lck(exitSync.mtx);
+
+            mg_printf(conn,
+                      "HTTP/1.1 200 OK\r\nContent-Type: "
+                      "text/plain\r\nConnection: close\r\n\r\n");
+            mg_printf(conn, "Server will begin periodically initiating epochs!\n");
+
+            exitSync.val2 = 1;
+            exitSync.cv.notify_all();
+
+            return true;
+        }
+};
+
+class ReadyHandler : public CivetHandler
+{
+    public:
+        bool handleGet(CivetServer *server, struct mg_connection *conn)
+        {
+            unique_lock<mutex> lck(readySync.mtx);
+
+            mg_printf(conn,
+                      "HTTP/1.1 200 OK\r\nContent-Type: "
+                      "text/plain\r\nConnection: close\r\n\r\n");
+            mg_printf(conn, "ACK\n");
+
+            readySync.val++;
+            readySync.cv.notify_all();
+
+            return true;
+        }
+};
+
+class EpochHandler : public CivetHandler
+{
+    public:
+        bool handleGet(CivetServer *server, struct mg_connection *conn)
+        {
+            mg_printf(conn,
+                      "HTTP/1.1 200 OK\r\nContent-Type: "
+                      "text/plain\r\nConnection: close\r\n\r\n");
+            mg_printf(conn, "%lu\n", epochNum);
+
+            return true;
+        }
+};
+
+int main(int argc, char *argv[])
+{
+    initialize_prsona_classes();
+
+#if USE_SSL
+    mg_init_library(0);
+#else
+    mg_init_library(MG_FEATURES_SSL);
+#endif
+    
+    const char *options[] = {"listening_ports", PRSONA_PORT, 0};
+
+    vector<string> serverIPs;
+    string selfIP, dealerIP;
+
+    char buffer[40];
+    ifstream serverConfig("serverIPs.cfg");
+    while (!serverConfig.eof())
+    {
+        serverConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            serverIPs.push_back(string(buffer));
+    }
+
+    ifstream selfConfig("selfIP.cfg");
+    while (!selfConfig.eof())
+    {
+        selfConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            selfIP = buffer;
+    }
+
+    ifstream dealerConfig("dealerIP.cfg");
+    while (!dealerConfig.eof())
+    {
+        dealerConfig.getline(buffer, 40);
+        if (strlen(buffer) > 0)
+            dealerIP = buffer;
+    }
+
+    // Defaults
+    size_t numServers = serverIPs.size();
+    bool bgnDealer = selfIP == dealerIP;
+    size_t timeToEpoch = 600;
+    bool maliciousServers = true;
+
+    if (argc > 1)
+        timeToEpoch = atoi(argv[1]);
+    if (argc > 2)
+    {
+        bool setting = argv[2][0] == 't' || argv[2][0] == 'T';
+        maliciousServers = setting;
+    }
+
+    cout << "Establishing PRSONA server with the following parameters: " << endl;
+    cout << numServers << " PRSONA servers" << endl;
+    if (bgnDealer)
+    {
+        cout << "This server IS the trusted BGN dealer" << endl;
+        cout << "The time between epochs is " << timeToEpoch << " seconds" << endl;
+    }
+    else
+    {
+        cout << "This server is NOT the trusted BGN dealer" << endl;
+    }
+    cout << "Servers are set to " << (maliciousServers ? "MALICIOUS" : "HBC") << " security" << endl;
+    cout << "This server is at IP address: " << selfIP << endl;
+    cout << "The BGN dealer is at IP address: " << dealerIP << endl;
+    cout << endl;
+
+    // Set malicious flags where necessary
+    if (maliciousServers)
+        PrsonaBase::set_server_malicious();
+
+    // Entities we operate with
+    PrsonaServer *prsonaServer;
+    if (bgnDealer)
+        prsonaServer = new PrsonaServer(numServers);
+    else
+    {
+        struct mg_connection *conn =
+            mg_connect_websocket_client(
+                dealerIP.c_str(),
+                PRSONA_PORT,
+                USE_SSL,
+                NULL,
+                0,
+                BGN_URI,
+                "null",
+                bgn_websocket_data_handler,
+                bgn_websocket_close_handler,
+                NULL);
+
+        if (!conn)
+        {
+            cerr << "Couldn't obtain BGN details" << endl;
+            return 1;
+        }
+
+        unique_lock<mutex> lck(bgnSync.mtx);
+        remove(BGN_TMP_FILE);
+        bgnSync.val = 0;
+        mg_websocket_client_write(
+            conn,
+            MG_WEBSOCKET_OPCODE_DATACOMPLETE,
+            "",
+            0);
+
+        while (!bgnSync.val)
+            bgnSync.cv.wait(lck);
+
+        prsonaServer = create_server_from_bgn_file(numServers);
+    }
+
+    CivetServer server(options);
+
+    PrsonaServerWebSocketHandler wsHandler(prsonaServer, &updateMtx, &epochNum, serverIPs, selfIP);
+    server.addWebSocketHandler("/ws", wsHandler);
+
+    ReadyHandler readyHandler;
+    server.addHandler(READY_URI, readyHandler);
+
+    if (bgnDealer)
+    {
+        unique_lock<mutex> lck(readySync.mtx);
+        readySync.val++;
+        while (readySync.val < numServers)
+            readySync.cv.wait(lck);
+
+        vector<Proof> pi;
+        Twistpoint freshGenerator =
+            get_generator(pi, prsonaServer, serverIPs, true);
+
+        handout_generator(pi, freshGenerator, prsonaServer, serverIPs, true);
+
+        Twistpoint blindGenerator =
+            get_generator(pi, prsonaServer, serverIPs, false);
+
+        handout_generator(pi, freshGenerator, prsonaServer, serverIPs, false);
+    }
+    else
+    {
+        stringstream sysString;
+        string data;
+
+        struct mg_connection *conn =
+            mg_connect_client(
+                dealerIP, 
+                PRSONA_PORT,
+                USE_SSL, 
+                NULL,
+                0);
+
+        sysString << "GET " << READY_URI << " HTTP/1.1\r\n";
+        sysString << "Host: " << dealerIP << "\r\n\r\n";
+        data = sysString.str();
+
+        mg_write(conn, data.c_str(), data.length());
+        mg_close_connection(conn);
+    }
+
+    ExitHandler exitHandler;
+    server.addHandler(EXIT_URI, exitHandler);
+
+    if (bgnDealer)
+    {
+        BeginHandler beginHandler;
+        server.addHandler(BEGIN_URI, beginHandler);
+
+        unique_lock<mutex> lck(exitSync.mtx);
+        while (!exitSync.val && !exitSync.val2)
+            exitSync.cv.wait(lck);
+
+        while (!exitSync.val)
+        {
+            epoch(prsonaServer);
+            exitSync.cv.waitFor(lck, chrono::seconds(timeToEpoch));
+        }
+    }
+    else
+    {
+        unique_lock<mutex> lck(exitSync.mtx);
+        while (!exitSync.val)
+            exitSync.cv.wait(lck)
+    }
+
+    mg_exit_library();
+
+    delete prsonaServer;
+
+    if (bgnDealer)
+    {
+        for (size_t i = 0; i < serverIPs.size(); i++)
+        {
+            if (serverIPs[i] == selfIP)
+                continue;
+
+            stringstream sysString;
+            string data;
+
+            struct mg_connection *conn =
+                mg_connect_client(
+                    serverIPs[i], 
+                    PRSONA_PORT,
+                    USE_SSL, 
+                    NULL,
+                    0);
+
+            sysString << "GET " << EXIT_URI << " HTTP/1.1\r\n";
+            sysString << "Host: " << serverIPs[i] << "\r\n\r\n";
+            data = sysString.str();
+
+            mg_write(conn, data.c_str(), data.length());
+            mg_close_connection(conn);
+        }
+    }
+
+    return 0;
+}