Browse Source

changes to HBC stuff (not yet debugged)

Stan Gurtler 2 years ago
parent
commit
ec1a914e9e
6 changed files with 851 additions and 6 deletions
  1. 2 0
      prsona/inc/base.hpp
  2. 68 0
      prsona/inc/networkServer.hpp
  3. 48 0
      prsona/inc/server.hpp
  4. 10 0
      prsona/src/base.cpp
  5. 582 5
      prsona/src/networkServer.cpp
  6. 141 1
      prsona/src/server.cpp

+ 2 - 0
prsona/inc/base.hpp

@@ -23,6 +23,8 @@ class PrsonaBase {
 
         // CONST GETTERS
         static size_t get_max_allowed_vote();
+        static bool is_server_malicious();
+        static bool is_client_malicious();
         Twistpoint get_blinding_generator() const;
         Twistpoint get_blinding_generator(
             std::vector<Proof>& pi

+ 68 - 0
prsona/inc/networkServer.hpp

@@ -115,6 +115,21 @@ std::vector<Proof> epoch_build_up(
     const std::string& usageFilename,
     std::vector<size_t>& bandwidthData);
 
+std::vector<Proof> hbc_epoch_build_up(
+    std::default_random_engine& rng,
+    PrsonaServer *prsonaServer,
+    const std::vector<std::string>& serverIPs,
+    const std::vector<int>& serverPorts,
+    const std::string& selfIP,
+    int selfPort,
+    Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    std::mutex& usageMtx,
+    const std::string& usageFilename,
+    std::vector<size_t>& overallBandwidthData);
+
 void epoch_break_down(
     std::default_random_engine& rng,
     PrsonaServer *prsonaServer,
@@ -131,6 +146,22 @@ void epoch_break_down(
     const std::string& usageFilename,
     std::vector<size_t>& bandwidthData);
 
+void hbc_epoch_break_down(
+    std::default_random_engine& rng,
+    PrsonaServer *prsonaServer,
+    const std::vector<std::string>& serverIPs,
+    const std::vector<int>& serverPorts,
+    const std::string& selfIP,
+    int selfPort,
+    const std::vector<Proof>& generatorProof,
+    const Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    std::mutex& usageMtx,
+    const std::string& usageFilename,
+    std::vector<size_t>& bandwidthData);
+
 // HELPERS FOR EPOCH HELPERS
 Twistpoint initiate_epoch_updates(
     std::default_random_engine& rng,
@@ -206,6 +237,15 @@ std::string make_epoch_update_string(
     const Twistpoint& nextGenerator,
     bool doUserTallies);
 
+std::string make_hbc_epoch_update_string(
+    const std::vector<Proof>& generatorProof,
+    const std::vector<Twistpoint>& newFreshPseudonyms,
+    const std::vector<CurveBipoint>& newServerTallies,
+    const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    const std::vector<EGCiphertext>& newUserTallies,
+    const Twistpoint& nextGenerator,
+    bool doUserTallies);
+
 ssize_t read_epoch_update_string(
     const char *filename,
     std::vector<std::vector<Proof>>& pi,
@@ -221,6 +261,16 @@ ssize_t read_epoch_update_string(
     Twistpoint& nextGenerator,
     bool& doUserTallies);
 
+ssize_t read_hbc_epoch_update_string(
+    const char *filename,
+    std::vector<Proof>& generatorProof,
+    std::vector<Twistpoint>& newFreshPseudonyms,
+    std::vector<CurveBipoint>& newServerTallies,
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    std::vector<Twistpoint>& newUserTallies,
+    Twistpoint& nextGenerator,
+    bool& doUserTallies);
+
 /* OTHER SERVER-RELEVANT HANDLERS */
 
 // Used to tell orchestrator when the system is ready to do an epoch change
@@ -496,18 +546,36 @@ class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
             const char *filename
         );
 
+        void hbc_build_up_midway_pseudonyms(
+            CivetServer *civetServer,
+            struct mg_connection *conn,
+            const char *filename
+        );
+
         void break_down_midway_pseudonyms(
             CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );
 
+        void hbc_break_down_midway_pseudonyms(
+            CivetServer *civetServer,
+            struct mg_connection *conn,
+            const char *filename
+        );
+
         void accept_epoch_updates(
             CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );
 
+        void hbc_accept_epoch_updates(
+            CivetServer *civetServer,
+            struct mg_connection *conn,
+            const char *filename
+        );
+
         // DISTRIBUTED BGN
         void get_partial_decryption(
             struct mg_connection *conn

+ 48 - 0
prsona/inc/server.hpp

@@ -124,6 +124,13 @@ class PrsonaServer : public PrsonaBase {
             std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>>& finalVoteMatrixCommits,
             Twistpoint& nextGenerator);
 
+        void hbc_build_up_midway_pseudonyms(
+            std::vector<Proof>& generatorProof,
+            std::vector<Twistpoint>& newFreshPseudonyms,
+            std::vector<CurveBipoint>& newServerTallies,
+            std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            Twistpoint& nextGenerator);
+
         void break_down_midway_pseudonyms(
             const std::vector<Proof>& generatorProof,
             std::vector<std::vector<std::vector<Proof>>>& pi,
@@ -138,6 +145,14 @@ class PrsonaServer : public PrsonaBase {
             std::vector<std::vector<std::vector<Twistpoint>>>& userTallySeedCommits,
             const Twistpoint& nextGenerator);
 
+        void hbc_break_down_midway_pseudonyms(
+            const std::vector<Proof>& generatorProof,
+            std::vector<Twistpoint>& newFreshPseudonyms,
+            std::vector<CurveBipoint>& newServerTallies,
+            std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            std::vector<EGCiphertext>& newUserTallies,
+            const Twistpoint& nextGenerator);
+
         bool accept_epoch_updates(
             const std::vector<std::vector<Proof>>& pi,
             const std::vector<std::vector<Twistpoint>>& permutationCommits,
@@ -152,6 +167,13 @@ class PrsonaServer : public PrsonaBase {
             const Twistpoint& nextGenerator,
             bool doUserTallies);
 
+        bool hbc_accept_epoch_updates(
+            const std::vector<Twistpoint>& newFreshPseudonyms,
+            const std::vector<CurveBipoint>& newServerTallies,
+            const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            const std::vector<EGCiphertext>& newUserTallies,
+            bool doUserTallies);
+
         // DATA MAINTENANCE
         void export_new_user_update(
             std::vector<CurveBipoint>& otherPreviousVoteTallies,
@@ -414,9 +436,29 @@ class PrsonaServer : public PrsonaBase {
             const Twistpoint& nextGenerator,
             bool doUserTallies);
 
+        void hbc_epoch_calculations(
+            std::vector<Twistpoint>& newFreshPseudonyms,
+            std::vector<CurveBipoint>& newServerTallies,
+            std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            std::vector<EGCiphertext>& newUserTallies,
+            const Scalar& power,
+            const Twistpoint& nextGenerator,
+            bool doUserTallies);
+
+        void hbc_shuffle_vote_matrix(
+            std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            const std::vector<std::vector<TwistBipoint>>& oldVoteMatrix,
+            const std::vector<size_t> shuffleOrder
+        ) const;
+
         std::vector<std::vector<Scalar>> generate_permutation_matrix(
             const Scalar& reorderSeed
         ) const;
+
+        std::vector<size_t> generate_hbc_shuffle(
+            const Scalar& reorderSeed
+        ) const;
+
         std::vector<std::vector<Twistpoint>> generate_commitment_matrix(
             const std::vector<std::vector<Scalar>>& permutations,
             std::vector<std::vector<Scalar>>& seeds
@@ -529,6 +571,12 @@ class PrsonaServer : public PrsonaBase {
             const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
             const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits);
 
+        bool hbc_update_data(
+            const std::vector<Twistpoint>& newFreshPseudonyms,
+            const std::vector<CurveBipoint>& newServerTallies,
+            const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+            const std::vector<EGCiphertext>& newUserTallies);
+
         bool pseudonyms_sorted(
             const std::vector<Twistpoint> newPseudonyms
         ) const;

+ 10 - 0
prsona/src/base.cpp

@@ -83,6 +83,16 @@ size_t PrsonaBase::get_max_allowed_vote()
     return MAX_ALLOWED_VOTE;
 }
 
+bool PrsonaBase::is_server_malicious()
+{
+    return SERVER_IS_MALICIOUS;
+}
+
+bool PrsonaBase::is_client_malicious()
+{
+    return CLIENT_IS_MALICIOUS;
+}
+
 Twistpoint PrsonaBase::get_blinding_generator() const
 {
     return elGamalBlindGenerator;

+ 582 - 5
prsona/src/networkServer.cpp

@@ -122,7 +122,11 @@ void make_epoch(
     obtain_update_locks(updateLock, serverIPs, serverPorts, selfIP, selfPort, bandwidthData);
 
     // Do the first half of the epoch calculations (building up the intermediary values)
-    std::vector<Proof> generatorProof = epoch_build_up(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, civetServer, buildUpOutputMtx, buildUpOutputFilename, usageMtx, usageFilename, bandwidthData);
+    std::vector<Proof> generatorProof;
+    if (prsonaServer->is_server_malicious())
+        generatorProof = epoch_build_up(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, civetServer, buildUpOutputMtx, buildUpOutputFilename, usageMtx, usageFilename, bandwidthData);
+    else
+        generatorProof = hbc_epoch_build_up(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, civetServer, buildUpOutputMtx, buildUpOutputFilename, usageMtx, usageFilename, bandwidthData);
 
     // Tally up the current scores at the end of the epoch for the users
     std::vector<EGCiphertext> currentUserEncryptedTallies;
@@ -133,7 +137,10 @@ void make_epoch(
     distribute_tallied_scores(prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, currentUserEncryptedTallies, currentServerEncryptedTallies, bandwidthData);
 
     // Do the second half of the epoch calculations (breaking down values to their final values, to be given to users)
-    epoch_break_down(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, generatorProof, nextGenerator, civetServer, breakDownOutputMtx, breakDownOutputFilename, usageMtx, usageFilename, bandwidthData);
+    if (prsonaServer->is_server_malicious())
+        epoch_break_down(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, generatorProof, nextGenerator, civetServer, breakDownOutputMtx, breakDownOutputFilename, usageMtx, usageFilename, bandwidthData);
+    else
+        hbc_epoch_break_down(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, generatorProof, nextGenerator, civetServer, breakDownOutputMtx, breakDownOutputFilename, usageMtx, usageFilename, bandwidthData);
 
     // Indicate we are in a new epoch
     epochNum.fetch_add(1);
@@ -595,6 +602,118 @@ std::vector<Proof> epoch_build_up(
     return generatorProofHolder[0];
 }
 
+std::vector<Proof> hbc_epoch_build_up(
+    std::default_random_engine& rng,
+    PrsonaServer *prsonaServer,
+    const std::vector<std::string>& serverIPs,
+    const std::vector<int>& serverPorts,
+    const std::string& selfIP,
+    int selfPort,
+    Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    std::mutex& usageMtx,
+    const std::string& usageFilename,
+    std::vector<size_t>& overallBandwidthData)
+{
+    std::vector<Proof> generatorProof;
+    std::vector<Twistpoint> newFreshPseudonyms;
+    std::vector<CurveBipoint> newServerTallies;
+    std::vector<std::vector<TwistBipoint>> newVoteMatrix;
+
+    // Go through each server to perform the epoch calculation at hand
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        // When it's our turn, do things as normal
+        if (serverIPs[i] == selfIP && serverPorts[i] == selfPort)
+        {
+            newFreshPseudonyms.clear();
+            newServerTallies.clear();
+            newVoteMatrix.clear();
+            std::vector<size_t> bandwidthData(2);
+            std::vector<std::vector<size_t>> otherBandwidthDataBefore;
+
+            std::vector<size_t> serverBandwidthDataBefore = get_server_log_data(civetServer.getContext());
+            std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+            clock_t cpuTimeBefore = clock();
+            
+            // Perform the actual calculation
+            prsonaServer->hbc_build_up_midway_pseudonyms(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, nextGenerator);
+
+            std::vector<EGCiphertext> newUserTallies;
+
+            // Serialize the relevant data
+            std::string data = make_hbc_epoch_update_string(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator, false);
+
+            struct synchronization_tool sync;
+            std::vector<struct mg_connection *> conns;
+
+            // Distribute the data to each server (in parallel, roughly)
+            std::unique_lock<std::mutex> lck(sync.mtx);
+            sync.val = 1;
+            for (size_t j = 0; j < serverIPs.size(); j++)
+            {
+                // But, obviously, don't send it back to ourselves
+                if (i == j)
+                    continue;
+
+                // Send that data
+                struct mg_connection *currConn = distribute_epoch_updates(serverIPs[j], serverPorts[j], data, &sync);
+
+                otherBandwidthDataBefore.push_back(get_conn_log_data(mg_get_context(currConn), false));
+
+                // But keep track of that connection, as we can't close it until we know the server's gotten its data
+                conns.push_back(currConn);
+            }
+
+            // Wait for the other servers to all report back that they have received the update
+            while (sync.val < serverIPs.size())
+                sync.cv.wait(lck);
+
+            for (size_t j = 0; j < conns.size(); j++)
+            {
+                std::vector<size_t> currBandwidthDataAfter = get_conn_log_data(mg_get_context(conns[j]), false);
+
+                bandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[j][0];
+                bandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[j][1];
+                overallBandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[j][0];
+                overallBandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[j][1];
+
+                mg_close_connection(conns[j]);
+            }
+
+            clock_t cpuTimeAfter = clock();
+            std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+            std::vector<size_t> serverBandwidthDataAfter = get_server_log_data(civetServer.getContext());
+
+            std::vector<double> timingData(2);
+            timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+            timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+            bandwidthData[0] += serverBandwidthDataAfter[0] - serverBandwidthDataBefore[0];
+            bandwidthData[1] += serverBandwidthDataAfter[1] - serverBandwidthDataBefore[1];
+
+            write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
+            write_usage_data(usageMtx, usageFilename);
+        }
+        else    // When it's another server's turn, tell them to do their part
+        {
+            // Serialize the request
+            std::string data = make_epoch_initiator_string(generatorProof, nextGenerator);
+
+            std::vector<std::vector<Proof>> generatorProofHolder;
+            generatorProofHolder.push_back(generatorProof);
+
+            // And have them do that request
+            nextGenerator = initiate_epoch_updates(rng, serverIPs[i], serverPorts[i], data, false, generatorProofHolder, overallBandwidthData);
+            generatorProof = generatorProofHolder[0];
+        }
+    }
+
+    return generatorProof;
+}
+
 void epoch_break_down(
     std::default_random_engine& rng,
     PrsonaServer *prsonaServer,
@@ -715,6 +834,114 @@ void epoch_break_down(
     }
 }
 
+void hbc_epoch_break_down(
+    std::default_random_engine& rng,
+    PrsonaServer *prsonaServer,
+    const std::vector<std::string>& serverIPs,
+    const std::vector<int>& serverPorts,
+    const std::string& selfIP,
+    int selfPort,
+    const std::vector<Proof>& generatorProof,
+    const Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    std::mutex& usageMtx,
+    const std::string& usageFilename,
+    std::vector<size_t>& overallBandwidthData)
+{
+    std::vector<Twistpoint> newFreshPseudonyms;
+    std::vector<CurveBipoint> newServerTallies;
+    std::vector<std::vector<TwistBipoint>> newVoteMatrix;
+    std::vector<EGCiphertext> newUserTallies;
+
+    // Go through each server to perform the epoch calculation at hand
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        // When it's our turn, do things as normal
+        if (serverIPs[i] == selfIP && serverPorts[i] == selfPort)
+        {
+            newFreshPseudonyms.clear();
+            newServerTallies.clear();
+            newVoteMatrix.clear();
+            newUserTallies.clear();
+            std::vector<size_t> bandwidthData(2);
+            std::vector<std::vector<size_t>> otherBandwidthDataBefore;
+
+            std::vector<size_t> serverBandwidthDataBefore = get_server_log_data(civetServer.getContext());
+            std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+            clock_t cpuTimeBefore = clock();
+
+            // Perform the actual calculation
+            prsonaServer->hbc_break_down_midway_pseudonyms(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator);
+
+            // Serialize the relevant data
+            std::string data = make_hbc_epoch_update_string(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator, true);
+
+            struct synchronization_tool sync;
+            std::vector<struct mg_connection *> conns;
+
+            // Distribute the data to each server (in parallel, roughly)
+            std::unique_lock<std::mutex> lck(sync.mtx);
+            sync.val = 1;
+            for (size_t j = 0; j < serverIPs.size(); j++)
+            {
+                // But, obviously, don't send it back to ourselves
+                if (i == j)
+                    continue;
+
+                // Send that data
+                struct mg_connection *currConn = distribute_epoch_updates(serverIPs[j], serverPorts[j], data, &sync);
+
+                otherBandwidthDataBefore.push_back(get_conn_log_data(mg_get_context(currConn), false));
+
+                // But keep track of that connection, as we can't close it until we know the server's gotten its data
+                conns.push_back(currConn);
+            }
+
+            // Wait for the other servers to all report back that they have received the update
+            while (sync.val < serverIPs.size())
+                sync.cv.wait(lck);
+
+            for (size_t j = 0; j < conns.size(); j++)
+            {
+                std::vector<size_t> currBandwidthDataAfter = get_conn_log_data(mg_get_context(conns[j]), false);
+
+                bandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[j][0];
+                bandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[j][1];
+                overallBandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[j][0];
+                overallBandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[j][1];
+
+                mg_close_connection(conns[j]);
+            }
+
+            clock_t cpuTimeAfter = clock();
+            std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+            std::vector<size_t> serverBandwidthDataAfter = get_server_log_data(civetServer.getContext());
+
+            std::vector<double> timingData(2);
+            timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+            timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+            bandwidthData[0] += serverBandwidthDataAfter[0] - serverBandwidthDataBefore[0];
+            bandwidthData[1] += serverBandwidthDataAfter[1] - serverBandwidthDataBefore[1];
+
+            write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
+            write_usage_data(usageMtx, usageFilename);
+        }
+        else    // When it's another server's turn, tell them to do their part
+        {
+            std::vector<std::vector<Proof>> unused;
+
+            // Serialize the request
+            std::string data = make_epoch_initiator_string(generatorProof, nextGenerator);
+            
+            // And have them do that request
+            initiate_epoch_updates(rng, serverIPs[i], serverPorts[i], data, true, unused, overallBandwidthData);
+        }
+    }
+}
+
 /*
  * HELPERS FOR EPOCH HELPERS
  */
@@ -1168,6 +1395,53 @@ std::string make_epoch_update_string(
     return buffer.str();
 }
 
+std::string make_hbc_epoch_update_string(
+    const std::vector<Proof>& generatorProof,
+    const std::vector<Twistpoint>& newFreshPseudonyms,
+    const std::vector<CurveBipoint>& newServerTallies,
+    const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    const std::vector<EGCiphertext>& newUserTallies,
+    const Twistpoint& nextGenerator,
+    bool doUserTallies)
+{
+    std::stringstream buffer;
+    
+    BinarySizeT sizeOfVector;
+
+    sizeOfVector.set(generatorProof.size());
+    buffer << sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+        buffer << generatorProof[i];
+
+    sizeOfVector.set(newFreshPseudonyms.size());
+    buffer << sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+        buffer << newFreshPseudonyms[i];
+
+    sizeOfVector.set(newServerTallies.size());
+    buffer << sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+        buffer << newServerTallies[i];
+
+    sizeOfVector.set(newVoteMatrix.size());
+    buffer << sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+        for (size_t j = 0; j < sizeOfVector.val(); j++)
+            buffer << newVoteMatrix[i][j];
+
+    sizeOfVector.set(newUserTallies.size());
+    buffer << sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+        buffer << newUserTallies[i];
+
+    buffer << nextGenerator;
+
+    BinaryBool flag(doUserTallies);
+    buffer << flag;
+
+    return buffer.str();
+}
+
 ssize_t read_epoch_update_string(
     const char *filename,
     std::vector<std::vector<Proof>>& pi,
@@ -1366,6 +1640,91 @@ ssize_t read_epoch_update_string(
     return retval;
 }
 
+ssize_t read_hbc_epoch_update_string(
+    const char *filename,
+    std::vector<Proof>& generatorProof,
+    std::vector<Twistpoint>& newFreshPseudonyms,
+    std::vector<CurveBipoint>& newServerTallies,
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    std::vector<EGCiphertext>& newUserTallies,
+    Twistpoint& nextGenerator,
+    bool& doUserTallies)
+{
+    std::ifstream file(filename);
+
+    file.ignore(std::numeric_limits<std::streamsize>::max());
+    std::streamsize retval = file.gcount();
+    file.clear();
+    file.seekg(0, std::ios_base::beg);
+
+    BinarySizeT sizeOfVector;
+    
+    generatorProof.clear();
+    newFreshPseudonyms.clear();
+    newServerTallies.clear();
+    newVoteMatrix.clear();
+    newUserTallies.clear();
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+    {
+        Proof currProof;
+        file >> currProof;
+
+        generatorProof.push_back(currProof);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+    {
+        Twistpoint currFreshPseudonym;
+        file >> currFreshPseudonym;
+
+        newFreshPseudonyms.push_back(currFreshPseudonym);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+    {
+        CurveBipoint currServerTally;
+        file >> currServerTally;
+
+        newServerTallies.push_back(currServerTally);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+    {
+        std::vector<TwistBipoint> currRow;
+        for (size_t j = 0; j < sizeOfVector.val(); j++)
+        {
+            TwistBipoint currVote;
+            file >> currVote;
+
+            currRow.push_back(currVote);    
+        }
+        newVoteMatrix.push_back(currRow);
+    }
+
+    file >> sizeOfVector;
+    for (size_t i = 0; i < sizeOfVector.val(); i++)
+    {
+        EGCiphertext currUserTally;
+        file >> currUserTally;
+
+        newUserTallies.push_back(currUserTally);
+    }
+
+    file >> nextGenerator;
+    
+    BinaryBool binaryDoUserTallies;
+    file >> binaryDoUserTallies;
+
+    doUserTallies = binaryDoUserTallies.val();
+
+    return retval;
+}
+
 /**********************************************************
  ****                                                  ****
  ****  other server-relevant handler member functions  ****
@@ -1782,15 +2141,24 @@ void PrsonaServerWebSocketHandler::generate_response(
 
         // EPOCH ROUNDS
         case PRSONA_PERFORM_EPOCH_BUILD_UP:
-            build_up_midway_pseudonyms(server, conn, filename);
+            if (prsonaServer->is_server_malicious())
+                build_up_midway_pseudonyms(server, conn, filename);
+            else
+                hbc_build_up_midway_pseudonyms(server, conn, filename);
             break;
 
         case PRSONA_PERFORM_EPOCH_BREAK_DOWN:
-            break_down_midway_pseudonyms(server, conn, filename);
+            if (prsonaServer->is_server_malicious())
+                break_down_midway_pseudonyms(server, conn, filename);
+            else
+                hbc_break_down_midway_pseudonyms(server, conn, filename);
             break;
 
         case PRSONA_RECEIVE_EPOCH_UPDATE:
-            accept_epoch_updates(server, conn, filename);
+            if (prsonaServer->is_server_malicious())
+                accept_epoch_updates(server, conn, filename);
+            else
+                hbc_accept_epoch_updates(server, conn, filename);
             break;
 
         // DISTRIBUTED BGN
@@ -2656,6 +3024,91 @@ void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
 }
 
+void PrsonaServerWebSocketHandler::hbc_build_up_midway_pseudonyms(
+    CivetServer *civetServer,
+    struct mg_connection *conn,
+    const char *filename)
+{
+    std::vector<Proof> generatorProof;
+    Twistpoint nextGenerator;
+
+    // Un-serialize request
+    ssize_t bandwidthRcv = read_epoch_initiator_string(filename, generatorProof, nextGenerator);
+
+    std::vector<Twistpoint> newFreshPseudonyms;
+    std::vector<CurveBipoint> newServerTallies;
+    std::vector<std::vector<TwistBipoint>> newVoteMatrix;
+
+    std::vector<size_t> bandwidthData(2);
+    std::vector<std::vector<size_t>> otherBandwidthDataBefore;
+
+    std::vector<size_t> serverBandwidthDataBefore = get_server_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
+    // Do actual epoch calculation
+    prsonaServer->hbc_build_up_midway_pseudonyms(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, nextGenerator);
+
+    std::vector<EGCiphertext> newUserTallies;
+
+    // Serialize update data
+    std::string data = make_hbc_epoch_update_string(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator, false);
+
+    struct synchronization_tool sync;
+    std::vector<struct mg_connection *> conns;
+
+    // Connect to all other servers (roughly in parallel)
+    std::unique_lock<std::mutex> lck(sync.mtx);
+    sync.val = 1;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP && serverPorts[i] == selfPort)
+            continue;
+
+        // Send them update data
+        struct mg_connection *currConn = distribute_epoch_updates(serverIPs[i], serverPorts[i], data, &sync);
+
+        conns.push_back(currConn);
+        otherBandwidthDataBefore.push_back(get_conn_log_data(mg_get_context(currConn), false));
+    }
+
+    // Wait for all to acknowledge receipt of the update data
+    while (sync.val < serverIPs.size())
+        sync.cv.wait(lck);
+
+    // Close connections
+    for (size_t i = 0; i < conns.size(); i++)
+    {
+        std::vector<size_t> currBandwidthDataAfter = get_conn_log_data(mg_get_context(conns[i]), false);
+
+        bandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[i][0];
+        bandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[i][1];
+
+        mg_close_connection(conns[i]);
+    }
+
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> serverBandwidthDataAfter = get_server_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    bandwidthData[0] += serverBandwidthDataAfter[0] - serverBandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] += serverBandwidthDataAfter[1] - serverBandwidthDataBefore[1];
+
+    write_log_data(buildUpOutputMtx, buildUpOutputFilename, timingData, bandwidthData);
+    write_usage_data(usageMtx, usageFilename);
+    
+    // Serialize response
+    data = make_epoch_initiator_string(generatorProof, nextGenerator);
+
+    // Send response
+    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(
     CivetServer *civetServer,
     struct mg_connection *conn,
@@ -2744,6 +3197,88 @@ void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
 }
 
+void PrsonaServerWebSocketHandler::hbc_break_down_midway_pseudonyms(
+    CivetServer *civetServer,
+    struct mg_connection *conn,
+    const char *filename)
+{
+    std::vector<Proof> generatorProof;
+    Twistpoint nextGenerator;
+
+    // Un-serialize request
+    ssize_t bandwidthRcv = read_epoch_initiator_string(filename, generatorProof, nextGenerator);
+
+    std::vector<Twistpoint> newFreshPseudonyms;
+    std::vector<CurveBipoint> newServerTallies;
+    std::vector<std::vector<TwistBipoint>> newVoteMatrix;
+    std::vector<EGCiphertext> newUserTallies;
+    std::vector<size_t> bandwidthData(2);
+    std::vector<std::vector<size_t>> otherBandwidthDataBefore;
+
+    std::vector<size_t> serverBandwidthDataBefore = get_server_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
+    // Perform the actual calculation
+    prsonaServer->hbc_break_down_midway_pseudonyms(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator);
+
+    // Serialize the relevant data
+    std::string data = make_hbc_epoch_update_string(generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator, true);
+
+    struct synchronization_tool sync;
+    std::vector<struct mg_connection *> conns;
+
+    // Connect to all other servers (roughly in parallel)
+    std::unique_lock<std::mutex> lck(sync.mtx);
+    sync.val = 1;
+    for (size_t i = 0; i < serverIPs.size(); i++)
+    {
+        if (serverIPs[i] == selfIP && serverPorts[i] == selfPort)
+            continue;
+
+        // Send them update data
+        struct mg_connection *currConn = distribute_epoch_updates(serverIPs[i], serverPorts[i], data, &sync);
+
+        conns.push_back(currConn);
+        otherBandwidthDataBefore.push_back(get_conn_log_data(mg_get_context(currConn), false));
+    }
+
+    // Wait for all to acknowledge receipt of the update data
+    while (sync.val < serverIPs.size())
+        sync.cv.wait(lck);
+
+    // Close connections
+    for (size_t i = 0; i < conns.size(); i++)
+    {
+        std::vector<size_t> currBandwidthDataAfter = get_conn_log_data(mg_get_context(conns[i]), false);
+
+        bandwidthData[0] += currBandwidthDataAfter[0] - otherBandwidthDataBefore[i][0];
+        bandwidthData[1] += currBandwidthDataAfter[1] - otherBandwidthDataBefore[i][1];
+
+        mg_close_connection(conns[i]);
+    }
+
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> serverBandwidthDataAfter = get_server_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    bandwidthData[0] += serverBandwidthDataAfter[0] - serverBandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] += serverBandwidthDataAfter[1] - serverBandwidthDataBefore[1];
+
+    write_log_data(breakDownOutputMtx, breakDownOutputFilename, timingData, bandwidthData);
+    write_usage_data(usageMtx, usageFilename);
+
+    // Keep our epoch value up-to-date
+    epochNum.fetch_add(1);
+
+    // Tell initiator we have finished
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
 void PrsonaServerWebSocketHandler::accept_epoch_updates(
     CivetServer *civetServer,
     struct mg_connection *conn,
@@ -2791,6 +3326,48 @@ void PrsonaServerWebSocketHandler::accept_epoch_updates(
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
 }
 
+void PrsonaServerWebSocketHandler::hbc_accept_epoch_updates(
+    CivetServer *civetServer,
+    struct mg_connection *conn,
+    const char *filename)
+{
+    std::vector<Proof> generatorProof;
+    std::vector<Twistpoint> newFreshPseudonyms;
+    std::vector<CurveBipoint> newServerTallies;
+    std::vector<std::vector<TwistBipoint>> newVoteMatrix;
+    std::vector<EGCiphertext> newUserTallies;
+    Twistpoint nextGenerator;
+    bool doUserTallies;
+
+    // Un-serialize request
+    ssize_t bandwidthRcv = read_hbc_epoch_update_string(filename, generatorProof, newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextGenerator, doUserTallies);
+
+    std::vector<size_t> bandwidthDataBefore = get_server_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
+    // Load data into server object
+    prsonaServer->hbc_accept_epoch_updates(newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, doUserTallies);
+
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_server_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(updateOutputMtx, updateOutputFilename, timingData, bandwidthData);
+    write_usage_data(usageMtx, usageFilename);
+
+    // Acknowledge receipt of request
+    mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
+}
+
 /*
  * DISTRIBUTED BGN
  */

+ 141 - 1
prsona/src/server.cpp

@@ -627,6 +627,22 @@ void PrsonaServer::build_up_midway_pseudonyms(
     nextGenerator = nextGenerator * nextSeed;
 }
 
+void PrsonaServer::hbc_build_up_midway_pseudonyms(
+    std::vector<Proof>& generatorProof,
+    std::vector<Twistpoint>& newFreshPseudonyms,
+    std::vector<CurveBipoint>& newServerTallies,
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    Twistpoint& nextGenerator)
+{
+    nextSeed.set_random();
+
+    std::vector<EGCiphertext> newUserTallies;
+    hbc_epoch_calculations(newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, nextSeed, nextGenerator, false);
+
+    generatorProof.push_back(add_to_generator_proof(nextGenerator, nextSeed));
+    nextGenerator = nextGenerator * nextSeed;
+}
+
 // In between these rounds, scores are tallied, decrypted,
 // and encrypted to fresh user pseudonyms (possible through weird math)
 
@@ -677,6 +693,27 @@ void PrsonaServer::break_down_midway_pseudonyms(
     currentSeed = nextSeed;
 }
 
+void PrsonaServer::hbc_break_down_midway_pseudonyms(
+    const std::vector<Proof>& generatorProof,
+    std::vector<Twistpoint>& newFreshPseudonyms,
+    std::vector<CurveBipoint>& newServerTallies,
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    std::vector<EGCiphertext>& newUserTallies,
+    const Twistpoint& nextGenerator)
+{
+    if (!initialize_fresh_generator(generatorProof, nextGenerator))
+    {
+        std::cerr << "New fresh generator could not be verified." << std::endl;
+        return;
+    }
+
+    Scalar inverseSeed = currentSeed.curveMultInverse();
+
+    hbc_epoch_calculations(newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies, inverseSeed, nextGenerator, true);
+
+    currentSeed = nextSeed;
+}
+
 /*
  * EPOCH HELPERS
  */
@@ -1032,6 +1069,63 @@ std::vector<std::vector<Proof>> PrsonaServer::epoch_calculations(
     return retval;
 }
 
+void PrsonaServer::hbc_epoch_calculations(
+    std::vector<Twistpoint>& newFreshPseudonyms,
+    std::vector<CurveBipoint>& newServerTallies,
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    std::vector<EGCiphertext>& newUserTallies,
+    const Scalar& power,
+    const Twistpoint& nextGenerator,
+    bool doUserTallies)
+{
+    std::vector<size_t> shuffleOrder = generate_hbc_shuffle(power);
+
+    newFreshPseudonyms.clear();
+    newServerTallies.clear();
+    newVoteMatrix.clear();
+    if (doUserTallies)
+        newUserTallies.clear();
+    for (size_t i = 0; i < shuffleOrder.size(); i++)
+    {
+        newFreshPseudonyms.push_back(currentPseudonyms[shuffleOrder[i]] * power);
+        newServerTallies.push_back(bgnSystem.rerandomize(previousVoteTallies[shuffleOrder[i]]));
+
+        if (doUserTallies)
+        {
+            Scalar r;
+            r.set_random();
+
+            EGCiphertext curr;
+            curr.mask = currentUserEncryptedTallies[shuffleOrder[i]].mask * power +
+                        newFreshPseudonyms[i] * r;
+            curr.encryptedMessage = currentUserEncryptedTallies[shuffleOrder[i]].encryptedMessage +
+                                    nextGenerator * r;
+
+            newUserTallies.push_back(curr);
+        }
+    }
+
+    hbc_shuffle_vote_matrix(newVoteMatrix, voteMatrix, shuffleOrder);
+
+    // Replace internal values
+    hbc_update_data(newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies);
+}
+
+void PrsonaServer::hbc_shuffle_vote_matrix(
+    std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    const std::vector<std::vector<TwistBipoint>>& oldVoteMatrix,
+    const std::vector<size_t> shuffleOrder) const
+{
+    for (size_t i = 0; i < shuffleOrder.size(); i++)
+    {
+        std::vector<TwistBipoint> currRow;
+        for (size_t j = 0; j < shuffleOrder.size(); j++)
+            currRow.push_back(bgnSystem.rerandomize(oldVoteMatrix[shuffleOrder[i]][shuffleOrder[j]]));
+
+        newVoteMatrix.push_back(currRow);
+    }
+}
+
 void verify_permutation_r(
     const void *a,
     void *b,
@@ -1186,7 +1280,7 @@ bool PrsonaServer::accept_epoch_updates(
 
     if ((userTallyMaskCommits.empty() && doUserTallies) || (!userTallyMaskCommits.empty() && !doUserTallies))
     {
-        std::cerr << "user tallies are not in expected state." << std::endl;
+        std::cerr << "User tallies are not in expected state." << std::endl;
         return false;
     }
 
@@ -1273,6 +1367,22 @@ bool PrsonaServer::accept_epoch_updates(
     return finalVerification;
 }
 
+bool PrsonaServer::hbc_accept_epoch_updates(
+    const std::vector<Twistpoint>& newFreshPseudonyms,
+    const std::vector<CurveBipoint>& newServerTallies,
+    const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    const std::vector<EGCiphertext>& newUserTallies,
+    bool doUserTallies)
+{
+    if ((newUserTallies.empty() && doUserTallies) || (!newUserTallies.empty() && !doUserTallies))
+    {
+        std::cerr << "User tallies are not in expected state." << std::endl;
+        return false;
+    }
+
+    return hbc_update_data(newFreshPseudonyms, newServerTallies, newVoteMatrix, newUserTallies);
+}
+
 std::vector<std::vector<Scalar>> PrsonaServer::generate_permutation_matrix(
     const Scalar& reorderSeed) const
 {
@@ -1298,6 +1408,16 @@ std::vector<std::vector<Scalar>> PrsonaServer::generate_permutation_matrix(
     return retval;
 }
 
+std::vector<size_t> PrsonaServer::generate_hbc_shuffle(
+    const Scalar& reorderSeed) const
+{
+    std::vector<Twistpoint> nextPseudonyms;
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+        nextPseudonyms.push_back(currentPseudonyms[i] * reorderSeed);
+
+    return sort_data(nextPseudonyms);
+}
+
 std::vector<std::vector<Twistpoint>> PrsonaServer::generate_commitment_matrix(
     const std::vector<std::vector<Scalar>>& permutations,
     std::vector<std::vector<Scalar>>& seeds) const
@@ -1779,6 +1899,26 @@ bool PrsonaServer::update_data(
     return true;
 }
 
+bool PrsonaServer::hbc_update_data(
+    const std::vector<Twistpoint>& newFreshPseudonyms,
+    const std::vector<CurveBipoint>& newServerTallies,
+    const std::vector<std::vector<TwistBipoint>>& newVoteMatrix,
+    const std::vector<EGCiphertext>& newUserTallies)
+{
+    if (!pseudonyms_sorted(newFreshPseudonyms))
+    {
+        std::cerr << "Pseudonyms not sorted correctly." << std::endl;
+        return false;
+    }
+
+    currentPseudonyms = newFreshPseudonyms;
+    previousVoteTallies = newServerTallies;
+    voteMatrix = newVoteMatrix;
+    currentUserEncryptedTallies = newUserTallies;
+
+    return true;
+}
+
 bool PrsonaServer::pseudonyms_sorted(
     const std::vector<Twistpoint> newPseudonyms) const
 {