Browse Source

cleanup of code to be more legible, and some minor changes in how the epoch is handled to be more appropriate for when networking is introduced

tristangurtler 3 years ago
parent
commit
6fedf2bb85
10 changed files with 1202 additions and 692 deletions
  1. 2 2
      prsona/Makefile
  2. 69 31
      prsona/inc/client.hpp
  3. 4 3
      prsona/inc/proof.hpp
  4. 135 43
      prsona/inc/server.hpp
  5. 22 19
      prsona/inc/serverEntity.hpp
  6. 280 243
      prsona/src/client.cpp
  7. 61 29
      prsona/src/main.cpp
  8. 42 0
      prsona/src/proof.cpp
  9. 363 147
      prsona/src/server.cpp
  10. 224 175
      prsona/src/serverEntity.cpp

+ 2 - 2
prsona/Makefile

@@ -24,8 +24,8 @@ BGN_BIN_PATH = $(BGN_PATH)/$(BIN_PATH)
 CPP = g++
 CPPFLAGS = -std=c++14 -Wall -I$(PRSONA_INC_PATH) -I$(BGN_INC_PATH) -I$(666_INC_PATH) -O2
 CPPTESTFLAGS = -std=c++14 -Wall -I$(PRSONA_INC_PATH) -I$(BGN_INC_PATH) -I$(666_INC_PATH) -g
-LDFLAGS = -lgmp -lgmpxx
-LDTESTFLAGS = -lgmp -lgmpxx -g
+LDFLAGS = -lgmp -lgmpxx -lssl -lcrypto
+LDTESTFLAGS = -lgmp -lgmpxx -lssl -lcrypto -g
 
 CC = gcc
 CFLAGS = -std=c99 -O3 -fomit-frame-pointer -I$(666_INC_PATH)

+ 69 - 31
prsona/inc/client.hpp

@@ -7,62 +7,100 @@
 #include "Curvepoint.hpp"
 #include "Scalar.hpp"
 #include "BGN.hpp"
+
 #include "EGCiphertext.hpp"
 #include "proof.hpp"
 
+// Forward declaration to be able to make a pointer to the servers,
+// which is needed in some proofs
+class PrsonaServerEntity;
+
 class PrsonaClient {
     public:
-        PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator);
+        // CONSTRUCTORS
+        PrsonaClient(
+            const BGNPublicKey& serverPublicKey,
+            const PrsonaServerEntity *servers);
 
-        static void set_malicious_server();
-        static void set_malicious_client();
+        // SETUP FUNCTIONS
+        static void init(const Curvepoint& elGamalBlindGenerator);
+        static void set_server_malicious();
+        static void set_client_malicious();
 
+        // BASIC PUBLIC SYSTEM INFO GETTERS
         Curvepoint get_short_term_public_key(Proof &pi) const;
 
-        void make_votes(Proof& pi, std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote, const std::vector<bool>& replace) const;
-
-        void receive_fresh_generator(const Proof& pi, const Curvepoint& freshGenerator);
-        void receive_vote_tally(const Proof& pi, const EGCiphertext& score, bool isDefault, const Scalar& randomizationMask);
-        void receive_encrypted_votes(const Proof& pi, const std::vector<CurveBipoint>& votes, bool isDefault);
+        // SERVER INTERACTIONS
+        std::vector<CurveBipoint> make_votes(
+            Proof& pi,
+            const std::vector<Scalar>& vote,
+            const std::vector<bool>& replace);
+        void receive_fresh_generator(const Curvepoint& freshGenerator);
+        void receive_vote_tally(const Proof& pi, const EGCiphertext& score);
+        void receive_encrypted_votes(
+            const Proof& pi, const std::vector<CurveBipoint>& votes);
         
-        std::vector<Proof> generate_reputation_proof(const Scalar& threshold) const;
-        bool verify_reputation_proof(const std::vector<Proof>& pi, const Curvepoint& shortTermPublicKey, const Scalar& threshold) const;
-
-        Proof generate_ownership_proof() const;
-        bool verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
+        // REPUTATION PROOFS
+        std::vector<Proof> generate_reputation_proof(
+            const Scalar& threshold) const;
+        bool verify_reputation_proof(
+            const std::vector<Proof>& pi,
+            const Curvepoint& shortTermPublicKey,
+            const Scalar& threshold) const;
 
     private:
-        static Curvepoint elGamalGenerator;
-        static bool malicious_server;
-        static bool malicious_client;
-        const BGNPublicKey serverPublicKey;
-        const Curvepoint elGamalBlindGenerator;
+        // Constants for clients
+        static Curvepoint EL_GAMAL_GENERATOR;
+        static Curvepoint EL_GAMAL_BLIND_GENERATOR;
+        static bool SERVER_IS_MALICIOUS;
+        static bool CLIENT_IS_MALICIOUS;
         
+        // Things bound to the servers permanently
+        const BGNPublicKey serverPublicKey;
+        const PrsonaServerEntity *servers;
+
+        // Things bound to the servers (but change regularly)
         Curvepoint currentFreshGenerator;
-        EGCiphertext currentEncryptedScore;
-        Scalar currentRandomizationMask;
 
+        // Things bound to this user permanently
         Scalar longTermPrivateKey;
         Scalar inversePrivateKey;
-        Scalar currentScore;
 
-        std::vector<CurveBipoint> currEncryptedVotes;
+        // Things bound to this user (but change regularly)
+        EGCiphertext currentEncryptedScore;
+        Scalar currentScore;
+        std::vector<CurveBipoint> currentEncryptedVotes;
 
-        std::unordered_map<Curvepoint, Scalar, CurvepointHash> decryption_memoizer;
+        // Things related to making decryption more efficient
+        std::unordered_map<Curvepoint, Scalar, CurvepointHash>
+            decryption_memoizer;
         Scalar max_checked;
 
+        // SCORE DECRYPTION
         void decrypt_score(const EGCiphertext& score);
 
-        Proof generate_stpk_proof() const;
-
-        bool verify_generator_proof(const Proof& pi, const Curvepoint& generator) const;
-        bool verify_default_tally_proof(const Proof& pi, const EGCiphertext& generator) const;
-        bool verify_valid_tally_proof(const Proof& pi, const EGCiphertext& score) const;
-        bool verify_default_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const;
-        bool verify_valid_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const;
+        // OWNERSHIP OF STPK PROOFS
+        Proof generate_ownership_proof() const;
+        bool verify_ownership_proof(
+            const Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
-        Proof generate_vote_proof(const std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote) const;
+        // PROOF VERIFICATION
         bool verify_score_proof(const Proof& pi) const;
+        bool verify_generator_proof(
+            const Proof& pi, const Curvepoint& generator) const;
+        bool verify_default_tally_proof(
+            const Proof& pi, const EGCiphertext& generator) const;
+        bool verify_valid_tally_proof(
+            const Proof& pi, const EGCiphertext& score) const;
+        bool verify_default_votes_proof(
+            const Proof& pi, const std::vector<CurveBipoint>& votes) const;
+        bool verify_valid_votes_proof(
+            const Proof& pi, const std::vector<CurveBipoint>& votes) const;
+
+        // PROOF GENERATION
+        Proof generate_vote_proof(
+            const std::vector<CurveBipoint>& encryptedVotes,
+            const std::vector<Scalar>& vote) const;
 }; 
 
 #endif

+ 4 - 3
prsona/inc/proof.hpp

@@ -1,15 +1,16 @@
 #ifndef __PROOF_HPP
 #define __PROOF_HPP
 
+#include <openssl/evp.h>
+#include <openssl/sha.h>
 #include <string>
 #include <vector>
 #include <sstream>
+#include <iomanip>
 
 #include "Scalar.hpp"
 #include "Curvepoint.hpp"
 
-// typedef std::string Proof;
-
 struct Proof {    
     std::string basic;
     std::vector<Curvepoint> partialUniversals;
@@ -18,7 +19,7 @@ struct Proof {
     std::vector<Scalar> responseParts;
 };
 
-Scalar oracle(std::string input);
+Scalar oracle(const std::string& input);
 
 #endif
 

+ 135 - 43
prsona/inc/server.hpp

@@ -11,56 +11,113 @@
 
 class PrsonaServer {
     public:
+        // CONSTRUCTORS
         PrsonaServer();
-        PrsonaServer(const BGN& other_bgn, const Curvepoint& other_blind_gen);
+        PrsonaServer(const BGN& other_bgn);
 
-        static void set_malicious_server();
-        static void set_malicious_client();
+        // SETUP FUNCTIONS
+        static Curvepoint init();
+        static void set_server_malicious();
+        static void set_client_malicious();
 
+        // BASIC PUBLIC SYSTEM INFO GETTERS
+        static Curvepoint get_blinding_generator();
         BGNPublicKey get_bgn_public_key() const;
-        Curvepoint get_blinding_generator() const;
-        Curvepoint add_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const;
-
-        std::vector<CurveBipoint> get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const;
-
-        void add_new_client(const Proof& proofOfValidKey, Proof& proofOfValidAddition, const Curvepoint& shortTermPublicKey);
-        void receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey);
+        
+        // FRESH GENERATOR CALCULATION
+        Curvepoint add_curr_seed_to_generator(
+            const Curvepoint& currGenerator) const;
+        Curvepoint add_next_seed_to_generator(
+            const Curvepoint& currGenerator) const;
+
+        // ENCRYPTED DATA GETTERS
+        std::vector<CurveBipoint> get_current_votes_by(
+            Proof& pi, const Curvepoint& shortTermPublicKey) const;
+        EGCiphertext get_current_tally(
+            Proof& pi, const Curvepoint& shortTermPublicKey) const;
+
+        // CLIENT INTERACTIONS
+        void add_new_client(
+            const Proof& proofOfValidKey,
+            Proof& proofOfValidAddition,
+            const Curvepoint& shortTermPublicKey);
+        void receive_vote(
+            const Proof& pi,
+            const std::vector<CurveBipoint>& votes,
+            const Curvepoint& shortTermPublicKey);
 
     private:
-        static Curvepoint elGamalGenerator;
-        static Scalar scalarN;
-        static Scalar defaultTally;
-        static Scalar defaultVote;
-        static bool malicious_server;
-        static bool malicious_client;
+        // Constants for servers
+        static Curvepoint EL_GAMAL_GENERATOR;
+        static Curvepoint EL_GAMAL_BLIND_GENERATOR;
+        static Scalar SCALAR_N;
+        static Scalar DEFAULT_TALLY;
+        static Scalar DEFAULT_VOTE;
+        static bool SERVER_IS_MALICIOUS;
+        static bool CLIENT_IS_MALICIOUS;
+
+        // Identical between all servers
         BGN bgn_system;
-        Curvepoint elGamalBlindGenerator;
 
+        // Private; different for each server
         Scalar currentSeed;
         Scalar nextSeed;
 
-        std::vector<TwistBipoint> previousVoteTally;
+        // The actual data, which is collaboratively updated by all servers
+        Curvepoint currentFreshGenerator;
+        std::vector<TwistBipoint> previousVoteTallies;
         std::vector<Curvepoint> currentPseudonyms;
-        /* each element represents a vote by <rowID>
-         * applied to <colID>. The outer std::vector is a std::vector of rows
-         * and the inner std::vector is a std::vector of curvepoints. */
+        std::vector<EGCiphertext> currentUserEncryptedTallies;
+        std::vector<Proof> currentTallyProofs;
         std::vector<std::vector<CurveBipoint>> voteMatrix;
 
+        /**
+         * NOTE: voteMatrix structure:
+         * Each element represents a vote by <rowID> applied to <colID>.
+         * The outer vector is a vector of rows and the inner vector is
+         * a vector of encrypted votes.
+         */
+
+        // An imaginary class; it's just used right now to coordinate servers
+        // in memory instead of via network action.
         friend class PrsonaServerEntity;
+
+        // CONSTRUCTOR HELPERS
         const BGN& get_bgn_details() const;
-        Curvepoint add_next_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const;
-        std::vector<Scalar> tally_scores(Proof& pi);
+        void initialize_fresh_generator(const Curvepoint& firstGenerator);
+        
+        // SCORE TALLYING
+        std::vector<Scalar> tally_scores(std::vector<Proof>& tallyProofs);
         Scalar get_max_possible_score(Proof& pi);
-        void export_updates(std::vector<TwistBipoint>& otherPreviousVoteTally, std::vector<Curvepoint>& otherCurrentPseudonyms, std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const;
-        void import_updates(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally, const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix);
-        void epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies, std::vector<Scalar>& encryptedTallyMasks);
-        void epoch_part_two(Proof& pi, const Curvepoint& nextGenerator, std::vector<EGCiphertext>& encryptedTallies, std::vector<Scalar>& encryptedTallyMasks);
-
-        std::vector<size_t> order_data();
-        void rerandomize_vote_matrix();
         
-        size_t binary_search(const Curvepoint& index) const;
-
+        // EPOCH ROUNDS
+        void build_up_midway_pseudonyms(
+            Proof& pi, Curvepoint& nextGenerator);
+        void break_down_midway_pseudonyms(
+            Proof& pi, const Curvepoint& nextGenerator);
+
+        // DATA MAINTENANCE
+        void import_updates(
+            const Proof& pi,
+            const std::vector<TwistBipoint>& otherPreviousVoteTally,
+            const std::vector<Curvepoint>& otherCurrentPseudonyms,
+            const std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
+            const std::vector<Proof>& otherCurrentTallyProofs,
+            const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix
+        );
+        void export_updates(
+            std::vector<TwistBipoint>& otherPreviousVoteTally,
+            std::vector<Curvepoint>& otherCurrentPseudonyms,
+            std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
+            std::vector<Proof>& otherCurrentTallyProofs,
+            std::vector<std::vector<CurveBipoint>>& otherVoteMatrix
+        ) const;
+
+        // DATA SAFEKEEPING
+        void rerandomize_data();
+        std::vector<size_t> order_data(Proof& pi);
+
+        // A helper class for "ordering" data and for binary search
         struct SortingType {
             Curvepoint pseudonym;
             size_t index;
@@ -68,18 +125,53 @@ class PrsonaServer {
             bool operator<( const SortingType& rhs ) const
                 { return pseudonym < rhs.pseudonym; }
         };
+        
+        // BINARY SEARCH
+        size_t binary_search(const Curvepoint& index) const;
 
-        bool verify_valid_key_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
-        bool verify_vote_proof(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const;
-        bool verify_update_proof(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally, const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const;
-
-        Proof generate_valid_fresh_generator_proof(const Proof& pi) const;
-        Proof generate_votes_valid_proof(const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const;
-        Proof generate_proof_of_added_user(const Curvepoint& shortTermPublicKey) const;
-        Proof generate_score_proof(const EGCiphertext& score) const;
-        Proof generate_proof_of_correct_tally(const std::vector<Quadripoint>& BGNEncryptedTallies, const std::vector<Scalar>& decryptedTallies) const;
-        Proof generate_proof_of_correct_sum(const TwistBipoint& BGNEncryptedSum, const Scalar& decryptedSum) const;
-        Proof generate_proof_of_shuffle(const std::vector<size_t>& shuffle_order) const;
+        // PROOF VERIFICATION
+        bool verify_valid_key_proof(
+            const Proof& pi,
+            const Curvepoint& shortTermPublicKey
+        ) const;
+        bool verify_vote_proof(
+            const Proof& pi,
+            const std::vector<CurveBipoint>& votes,
+            const Curvepoint& shortTermPublicKey
+        ) const;
+        bool verify_update_proof(
+            const Proof& pi
+        ) const;
+
+        // PROOF GENERATION
+        Proof generate_valid_default_tally_proof(
+            const EGCiphertext& newUserEncryptedTally,
+            const Scalar& mask
+        ) const;
+        Proof generate_valid_fresh_generator_proof(
+            const Proof& pi
+        ) const;
+        Proof generate_votes_valid_proof(
+            const std::vector<CurveBipoint>& votes,
+            const Curvepoint& voter
+        ) const;
+        Proof generate_proof_of_added_user(
+            const Curvepoint& shortTermPublicKey
+        ) const;
+        Proof generate_score_proof(
+            const EGCiphertext& score
+        ) const;
+        Proof generate_proof_of_correct_tally(
+            const Quadripoint& BGNEncryptedTally,
+            const Scalar& decryptedTally
+        ) const;
+        Proof generate_proof_of_correct_sum(
+            const TwistBipoint& BGNEncryptedSum,
+            const Scalar& decryptedSum
+        ) const;
+        Proof generate_proof_of_shuffle(
+            const std::vector<size_t>& shuffle_order
+        ) const;
 }; 
 
 #endif

+ 22 - 19
prsona/inc/serverEntity.hpp

@@ -9,36 +9,39 @@
 
 class PrsonaServerEntity {
     public:
+        // CONSTRUCTORS
         PrsonaServerEntity(size_t numServers);
 
+        // BASIC PUBLIC SYSTEM INFO GETTERS
         BGNPublicKey get_bgn_public_key() const;
         Curvepoint get_blinding_generator() const;
-        Curvepoint get_fresh_generator(Proof& pi) const;
-        Scalar decrypt(const CurveBipoint& input);
+        Curvepoint get_fresh_generator() const;
 
-        std::vector<CurveBipoint> get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const;
-        EGCiphertext get_current_tally(const Proof& ownerProof, Proof& serverProof, const Curvepoint& shortTermPublicKey, bool isOwner, Scalar& randomizationMask) const;
+        // ENCRYPTED DATA GETTERS
+        std::vector<CurveBipoint> get_current_votes_by(
+            Proof& pi, const Curvepoint& shortTermPublicKey) const;
+        EGCiphertext get_current_tally(
+            Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
+        // CLIENT INTERACTIONS
         void add_new_client(PrsonaClient& newUser);
-        void receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey);
-        void epoch();
-        void transmit_score(PrsonaClient& currUser) const;
+        void receive_vote(
+            const Proof& pi,
+            const std::vector<CurveBipoint>& votes,
+            const Curvepoint& shortTermPublicKey);
+        void transmit_updates(PrsonaClient& currUser) const;
+
+        // EPOCH
+        void epoch(Proof& pi);
 
     private:
         std::vector<PrsonaServer> servers;
-        std::vector<EGCiphertext> encryptedTallies;
-        std::vector<Scalar> encryptedTallyMasks;
-        std::vector<Proof> tallyProofs;
-
-        EGCiphertext get_default_tally(Proof& pi, const Curvepoint& shortTermPublicKey, Scalar& randomizationMask) const;
-        Proof generate_valid_default_tally_proof(const EGCiphertext& encryptedDefaultTally, const Scalar& lambda) const;
-
-        Proof generate_epoch_round_one_proof(const Proof& pi1, const Proof& pi2) const;
-        Proof generate_epoch_proof(const Proof& pi, const EGCiphertext& encryptedTally) const;
-
-        bool verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
-        std::vector<Scalar> tally_scores(Proof& pi);
+        // SCORE TALLYING
+        std::vector<EGCiphertext> tally_scores(
+            std::vector<Proof>& tallyProofs, const Curvepoint& nextGenerator);
+        
+        // BINARY SEARCH
         size_t binary_search(const Curvepoint& index) const;
 }; 
 

+ 280 - 243
prsona/src/client.cpp

@@ -1,14 +1,21 @@
 #include <iostream>
 
 #include "client.hpp"
+#include "serverEntity.hpp"
 
 extern const curvepoint_fp_t bn_curvegen;
-
-Curvepoint PrsonaClient::elGamalGenerator = Curvepoint();
-
-bool PrsonaClient::malicious_server = false;
-bool PrsonaClient::malicious_client = false;
-
+const int MAX_ALLOWED_VOTE = 2;
+
+/* These lines need to be here so these static variables are defined,
+ * but in C++ putting code here doesn't actually execute
+ * (or at least, with g++, whenever it would execute is not at a useful time)
+ * so we have an init() function to actually put the correct values in them. */
+Curvepoint PrsonaClient::EL_GAMAL_GENERATOR = Curvepoint();
+Curvepoint PrsonaClient::EL_GAMAL_BLIND_GENERATOR = Curvepoint();
+bool PrsonaClient::SERVER_IS_MALICIOUS = false;
+bool PrsonaClient::CLIENT_IS_MALICIOUS = false;
+
+// Quick and dirty function to calculate ceil(log base 2) with mpz_class
 mpz_class log2(mpz_class x)
 {
     mpz_class retval = 0;
@@ -21,37 +28,70 @@ mpz_class log2(mpz_class x)
     return retval;
 }
 
-PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator)
-: serverPublicKey(serverPublicKey), elGamalBlindGenerator(elGamalBlindGenerator), max_checked(0)
-{
-    elGamalGenerator = Curvepoint(bn_curvegen);
+/********************
+ * PUBLIC FUNCTIONS *
+ ********************/
 
+/*
+ * CONSTRUCTORS
+ */
+
+PrsonaClient::PrsonaClient(
+    const BGNPublicKey& serverPublicKey,
+    const PrsonaServerEntity* servers)
+    : serverPublicKey(serverPublicKey),
+        servers(servers),
+        max_checked(0)
+{
     longTermPrivateKey.set_random();
     inversePrivateKey = longTermPrivateKey.curveInverse();
 
-    decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
+    decryption_memoizer[EL_GAMAL_BLIND_GENERATOR * max_checked] = max_checked;
 }
 
-void PrsonaClient::set_malicious_server()
+/*
+ * SETUP FUNCTIONS
+ */
+
+// Must be called once before any usage of this class
+void PrsonaClient::init(const Curvepoint& elGamalBlindGenerator)
 {
-    malicious_server = true;
+    EL_GAMAL_GENERATOR = Curvepoint(bn_curvegen);
+    EL_GAMAL_BLIND_GENERATOR = elGamalBlindGenerator;
 }
 
-void PrsonaClient::set_malicious_client()
+void PrsonaClient::set_server_malicious()
 {
-    malicious_client = true;
+    SERVER_IS_MALICIOUS = true;
 }
 
-Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const
+void PrsonaClient::set_client_malicious()
 {
-    pi = generate_stpk_proof();
+    CLIENT_IS_MALICIOUS = true;
+}
+
+/*
+ * BASIC PUBLIC SYSTEM INFO GETTERS
+ */
 
+Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const
+{
+    pi = generate_ownership_proof();
     return currentFreshGenerator * longTermPrivateKey;
 }
 
-void PrsonaClient::make_votes(Proof& pi, std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote, const std::vector<bool>& replace) const
+/*
+ * SERVER INTERACTIONS
+ */
+
+// Generate a new vote vector to give to the servers
+// (@replace controls which votes are actually being updated and which are not)
+std::vector<CurveBipoint> PrsonaClient::make_votes(
+    Proof& pi,
+    const std::vector<Scalar>& vote,
+    const std::vector<bool>& replace)
 {
-    encryptedVotes.clear();
+    std::vector<CurveBipoint> retval;
 
     for (size_t i = 0; i < vote.size(); i++)
     {
@@ -59,79 +99,64 @@ void PrsonaClient::make_votes(Proof& pi, std::vector<CurveBipoint>& encryptedVot
         if (replace[i])
             serverPublicKey.encrypt(currScore, vote[i]);
         else
-            currScore = serverPublicKey.rerandomize(currEncryptedVotes[i]);
+            currScore = serverPublicKey.rerandomize(currentEncryptedVotes[i]);
 
-        encryptedVotes.push_back(currScore);
+        retval.push_back(currScore);
     }
 
-    pi = generate_vote_proof(encryptedVotes, vote);
+    currentEncryptedVotes = retval;
+
+    pi = generate_vote_proof(retval, vote);
+    return retval;
 }
 
-void PrsonaClient::receive_fresh_generator(const Proof& pi, const Curvepoint& freshGenerator)
+// Get a new fresh generator (happens at initialization and during each epoch)
+void PrsonaClient::receive_fresh_generator(const Curvepoint& freshGenerator)
 {
-    if (!verify_generator_proof(pi, freshGenerator))
-    {
-        std::cerr << "Could not verify proof of valid fresh generator." << std::endl;
-        return;
-    }
-
     currentFreshGenerator = freshGenerator;
 }
 
-void PrsonaClient::receive_vote_tally(const Proof& pi, const EGCiphertext& score, bool isDefault, const Scalar& randomizationMask)
+// Receive a new encrypted score from the servers (each epoch)
+void PrsonaClient::receive_vote_tally(
+    const Proof& pi, const EGCiphertext& score)
 {
-    if (isDefault)
-    {
-        if (!verify_default_tally_proof(pi, score))
-        {
-            std::cerr << "Could not verify proof of valid default tally." << std::endl;
-            return;
-        }
-    }
-    else
+    if (!verify_valid_tally_proof(pi, score))
     {
-        if (!verify_valid_tally_proof(pi, score))
-        {
-            std::cerr << "Could not verify proof of valid tally." << std::endl;
-            return;
-        }
+        std::cerr << "Could not verify proof of valid tally." << std::endl;
+        return;
     }
 
     currentEncryptedScore = score;
-    currentRandomizationMask = randomizationMask;
     decrypt_score(score);
 }
 
-void PrsonaClient::receive_encrypted_votes(const Proof& pi, const std::vector<CurveBipoint>& votes, bool isDefault)
+// Receive a new encrypted vote vector from the servers (each epoch)
+void PrsonaClient::receive_encrypted_votes(
+    const Proof& pi, const std::vector<CurveBipoint>& votes)
 {
-    if (isDefault)
+    if (!verify_valid_votes_proof(pi, votes))
     {
-        if (!verify_default_votes_proof(pi, votes))
-        {
-            std::cerr << "Could not verify proof of valid default votes." << std::endl;
-            return;
-        }
-    }
-    else
-    {
-        if (!verify_valid_votes_proof(pi, votes))
-        {
-            std::cerr << "Could not verify proof of valid votes." << std::endl;
-            return;
-        }
+        std::cerr << "Could not verify proof of valid votes." << std::endl;
+        return;
     }
 
-    currEncryptedVotes = votes;
+    currentEncryptedVotes = votes;
 }
 
-std::vector<Proof> PrsonaClient::generate_reputation_proof(const Scalar& threshold) const
+/*
+ * REPUTATION PROOFS
+ */
+
+// TO BE UPDATED WITH THING IAN SHOWED ME IN MEETING FOR DISJUNCTION
+std::vector<Proof> PrsonaClient::generate_reputation_proof(
+    const Scalar& threshold) const
 {
     std::vector<Proof> retval;
 
     if (threshold > currentScore)
         return retval;
 
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
     {
         Proof currProof;
         currProof.basic = "PROOF";
@@ -140,277 +165,297 @@ std::vector<Proof> PrsonaClient::generate_reputation_proof(const Scalar& thresho
         return retval;
     }
 
-    // retval.push_back(generate_ownership_proof());
+    retval.push_back(generate_ownership_proof());
 
-    // mpz_class proofVal = currentScore.curveSub(threshold).toInt();
-    // mpz_class proofBits = log2(currEncryptedVotes.size() * 3 - threshold.toInt());
+    mpz_class proofVal = currentScore.curveSub(threshold).toInt();
+    mpz_class proofBits = log2(currentEncryptedVotes.size() * MAX_ALLOWED_VOTE - threshold.toInt());
 
-    // std::vector<Scalar> masksPerBit;
-    // masksPerBit.push_back(currentRandomizationMask);
-    // for (size_t i = 1; i < proofBits; i++)
-    // {
-    //     Scalar currMask;
-    //     currMask.set_random();
+    std::vector<Scalar> masksPerBit;
+    masksPerBit.push_back(Scalar());
+    for (size_t i = 1; i < proofBits; i++)
+    {
+        Scalar currMask;
+        currMask.set_random();
 
-    //     masksPerBit.push_back(currMask);
-    //     masksPerBit[0] = masksPerBit[0].curveSub(currMask.curveMult(Scalar(1 << i)));
-    // }
+        masksPerBit.push_back(currMask);
+        masksPerBit[0] = masksPerBit[0].curveSub(currMask.curveMult(Scalar(1 << i)));
+    }
 
-    // for (size_t i = 0; i < proofBits; i++)
-    // {
-    //     Proof currProof;
-    //     std::stringstream oracleInput;
-    //     oracleInput << currentFreshGenerator << elGamalBlindGenerator;
+    for (size_t i = 0; i < proofBits; i++)
+    {
+        Proof currProof;
+        std::stringstream oracleInput;
+        oracleInput << currentFreshGenerator << EL_GAMAL_BLIND_GENERATOR;
     
-    //     mpz_class currBit = proofVal & (1 << i);
+        mpz_class currBit = proofVal & (1 << i);
         
-    //     Curvepoint currentCommitment = currentFreshGenerator * masksPerBit[i] + elGamalBlindGenerator * Scalar(currBit);
-    //     currProof.partialUniversals.push_back(currentCommitment);
-    //     oracleInput << currentCommitment;
-
-    //     if (currBit)
-    //     {
-    //         Scalar u_0, c, c_0, c_1, z_0, z_1;
-    //         u_0.set_random();
-    //         c_1.set_random();
-    //         z_1.set_random();
-
-    //         Curvepoint U_0 = currentFreshGenerator * u_0;
-    //         Curvepoint U_1 = currentFreshGenerator * z_1 - currentCommitment * c_1 + elGamalBlindGenerator;
-    //         currProof.initParts.push_back(U_0);
-    //         currProof.initParts.push_back(U_1);
-    //         oracleInput << U_0 << U_1;
-
-    //         c = oracle(oracleInput.str());
-    //         c_0 = c.curveSub(c_1);
-    //         z_0 = c_0.curveMult(masksPerBit[i]).curveAdd(u_0);
-
-    //         currProof.challengeParts.push_back(c_0);
-    //         currProof.challengeParts.push_back(c_1);
-    //         currProof.responseParts.push_back(z_0);
-    //         currProof.responseParts.push_back(z_1);
-    //     }
-    //     else
-    //     {
-    //         Scalar u_1, c, c_0, c_1, z_0, z_1;
-    //         u_1.set_random();
-    //         c_0.set_random();
-    //         z_0.set_random();
-
-    //         Curvepoint U_0 = currentFreshGenerator * z_0 - currentCommitment * c_0;
-    //         Curvepoint U_1 = currentFreshGenerator * u_1;
-    //         currProof.initParts.push_back(U_0);
-    //         currProof.initParts.push_back(U_1);
-    //         oracleInput << U_0 << U_1;
-
-    //         c = oracle(oracleInput.str());
-    //         c_1 = c.curveSub(c_0);
-    //         z_1 = c_1.curveMult(masksPerBit[i]).curveAdd(u_1);
-
-    //         currProof.challengeParts.push_back(c_0);
-    //         currProof.challengeParts.push_back(c_1);
-    //         currProof.responseParts.push_back(z_0);
-    //         currProof.responseParts.push_back(z_1);
-    //     }
-
-    //     retval.push_back(currProof);
-    // }
-
-    // return retval;
-
-    Proof currProof;
-    currProof.basic = "PROOF";
-
-    retval.push_back(currProof);
+        Curvepoint currentCommitment = currentFreshGenerator * masksPerBit[i] + EL_GAMAL_BLIND_GENERATOR * Scalar(currBit);
+        currProof.partialUniversals.push_back(currentCommitment);
+        oracleInput << currentCommitment;
+
+        if (currBit)
+        {
+            Scalar u_0, c, c_0, c_1, z_0, z_1;
+            u_0.set_random();
+            c_1.set_random();
+            z_1.set_random();
+
+            Curvepoint U_0 = currentFreshGenerator * u_0;
+            Curvepoint U_1 = currentFreshGenerator * z_1 - currentCommitment * c_1 + EL_GAMAL_BLIND_GENERATOR;
+            currProof.initParts.push_back(U_0);
+            currProof.initParts.push_back(U_1);
+            oracleInput << U_0 << U_1;
+
+            c = oracle(oracleInput.str());
+            c_0 = c.curveSub(c_1);
+            z_0 = c_0.curveMult(masksPerBit[i]).curveAdd(u_0);
+
+            currProof.challengeParts.push_back(c_0);
+            currProof.challengeParts.push_back(c_1);
+            currProof.responseParts.push_back(z_0);
+            currProof.responseParts.push_back(z_1);
+        }
+        else
+        {
+            Scalar u_1, c, c_0, c_1, z_0, z_1;
+            u_1.set_random();
+            c_0.set_random();
+            z_0.set_random();
+
+            Curvepoint U_0 = currentFreshGenerator * z_0 - currentCommitment * c_0;
+            Curvepoint U_1 = currentFreshGenerator * u_1;
+            currProof.initParts.push_back(U_0);
+            currProof.initParts.push_back(U_1);
+            oracleInput << U_0 << U_1;
+
+            c = oracle(oracleInput.str());
+            c_1 = c.curveSub(c_0);
+            z_1 = c_1.curveMult(masksPerBit[i]).curveAdd(u_1);
+
+            currProof.challengeParts.push_back(c_0);
+            currProof.challengeParts.push_back(c_1);
+            currProof.responseParts.push_back(z_0);
+            currProof.responseParts.push_back(z_1);
+        }
+
+        retval.push_back(currProof);
+    }
+
     return retval;
 }
 
-bool PrsonaClient::verify_reputation_proof(const std::vector<Proof>& pi, const Curvepoint& shortTermPublicKey, const Scalar& threshold) const
+// TO BE UPDATED WITH THING IAN SHOWED ME IN MEETING FOR DISJUNCTION
+bool PrsonaClient::verify_reputation_proof(
+    const std::vector<Proof>& pi,
+    const Curvepoint& shortTermPublicKey,
+    const Scalar& threshold) const
 {
     if (pi.empty())
         return false;
 
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
         return pi[0].basic == "PROOF";
 
-    // if (!verify_ownership_proof(pi[0], shortTermPublicKey))
-    //     return false;
-
-    // Curvepoint X;
-    // for (size_t i = 1; i < pi.size(); i++)
-    // {
-    //     X = X + pi[i].partialUniversals[0] * Scalar(1 << (i - 1));
-
-    //     std::stringstream oracleInput;
-    //     oracleInput << currentFreshGenerator << elGamalBlindGenerator << pi[i].partialUniversals[0];
-    //     oracleInput << pi[i].initParts[0] << pi[i].initParts[1];
-
-    //     Scalar c = oracle(oracleInput.str());
-
-    //     if (c != pi[i].challengeParts[0] + pi[i].challengeParts[1])
-    //         return false;
-
-    //     if (currentFreshGenerator * pi[i].responseParts[0] != pi[i].initParts[0] + pi[i].partialUniversals[0] * pi[i].challengeParts[0])
-    //         return false;
-
-    //     if (currentFreshGenerator * pi[i].responseParts[1] != pi[i].initParts[1] + pi[i].partialUniversals[0] * pi[i].challengeParts[1] - elGamalBlindGenerator)
-    //         return false;
-    // }
+    if (!verify_ownership_proof(pi[0], shortTermPublicKey))
+        return false;
 
-    // Proof unused, serverProof;
-    // Scalar alsoUnused;
-    // EGCiphertext encryptedScore = servers.get_current_tally(unused, serverProof, shortTermPublicKey, false, alsoUnused);
+    Curvepoint X;
+    for (size_t i = 1; i < pi.size(); i++)
+    {
+        X = X + pi[i].partialUniversals[0] * Scalar(1 << (i - 1));
 
-    // Scalar negThreshold;
-    // negThreshold = Scalar(0).curveSub(threshold);
+        std::stringstream oracleInput;
+        oracleInput << currentFreshGenerator << EL_GAMAL_BLIND_GENERATOR << pi[i].partialUniversals[0];
+        oracleInput << pi[i].initParts[0] << pi[i].initParts[1];
 
-    // Curvepoint scoreCommitment = encryptedScore.encryptedMessage + elGamalBlindGenerator * negThreshold;
-    // if (X != scoreCommitment)
-    //     return false;
+        Scalar c = oracle(oracleInput.str());
 
-    // return true;
+        if (c != pi[i].challengeParts[0] + pi[i].challengeParts[1])
+            return false;
 
-    return pi[0].basic == "PROOF";
-}
+        if (currentFreshGenerator * pi[i].responseParts[0] != pi[i].initParts[0] + pi[i].partialUniversals[0] * pi[i].challengeParts[0])
+            return false;
 
-Proof PrsonaClient::generate_ownership_proof() const
-{
-    Proof retval;
-    if (!malicious_client)
-    {
-        retval.basic = "PROOF";
-        return retval;
+        if (currentFreshGenerator * pi[i].responseParts[1] != pi[i].initParts[1] + pi[i].partialUniversals[0] * pi[i].challengeParts[1] - EL_GAMAL_BLIND_GENERATOR)
+            return false;
     }
 
-    // std::stringstream oracleInput;
-    
-    // Scalar r;
-    // r.set_random();
-
-    // Curvepoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey;
-    // Curvepoint u = currentFreshGenerator * r;
-    // oracleInput << currentFreshGenerator << shortTermPublicKey << u;
+    Proof serverProof;
+    EGCiphertext encryptedScore = servers->get_current_tally(serverProof, shortTermPublicKey);
 
-    // Scalar c = oracle(oracleInput.str());
-    // Scalar z = r.curveAdd(c.curveMult(longTermPrivateKey));
+    if (!verify_valid_tally_proof(serverProof, encryptedScore))
+        return false;
 
-    // retval.basic = "PROOF";
-    // retval.initParts.push_back(u);
-    // retval.responseParts.push_back(z);
+    Scalar negThreshold;
+    negThreshold = Scalar(0).curveSub(threshold);
 
-    // return retval;
+    Curvepoint scoreCommitment = encryptedScore.encryptedMessage + EL_GAMAL_BLIND_GENERATOR * negThreshold;
+    if (X != scoreCommitment)
+        return false;
 
-    retval.basic = "PROOF";
-    return retval;
+    return true;
 }
 
-bool PrsonaClient::verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
-{
-    if (!malicious_client)
-        return pi.basic == "PROOF";
-
-    // Curvepoint u = pi.initParts[0];
-
-    // std::stringstream oracleInput;
-    // oracleInput << currentFreshGenerator << shortTermPublicKey << u;
-    // Scalar c = oracle(oracleInput.str());
+/*********************
+ * PRIVATE FUNCTIONS *
+ *********************/
 
-    // Scalar z = pi.responseParts[0];
-
-    // return (currentFreshGenerator * z) == (shortTermPublicKey * c + u);
-
-    return pi.basic == "PROOF";
-}
+/*
+ * SCORE DECRYPTION
+ */
 
+// Basic memoized score decryption
 void PrsonaClient::decrypt_score(const EGCiphertext& score)
 {
     Curvepoint s, hashedDecrypted;
+
+    // Remove the mask portion of the ciphertext
     s = score.mask * inversePrivateKey;
     hashedDecrypted = score.encryptedMessage - s;
     
+    // Check if it's a value we've already seen
     auto lookup = decryption_memoizer.find(hashedDecrypted);
     if (lookup != decryption_memoizer.end())
     {
         currentScore = lookup->second;
-        // std::cout << "Decrypted score: " << currentScore << std::endl;
         return;
     }
 
+    // If not, iterate until we find it (adding everything to the memoization)
     max_checked++;
-    Curvepoint decryptionCandidate = elGamalBlindGenerator * max_checked;
-
+    Curvepoint decryptionCandidate = EL_GAMAL_BLIND_GENERATOR * max_checked;
     while (decryptionCandidate != hashedDecrypted)
     {
         decryption_memoizer[decryptionCandidate] = max_checked;
 
-        decryptionCandidate = decryptionCandidate + elGamalBlindGenerator;
+        decryptionCandidate = decryptionCandidate + EL_GAMAL_BLIND_GENERATOR;
         max_checked++;
     }
-
     decryption_memoizer[decryptionCandidate] = max_checked;
+
+    // Set the value we found
     currentScore = max_checked;
-    // std::cout << "Decrypted score: " << currentScore << std::endl;
 }
 
-Proof PrsonaClient::generate_stpk_proof() const
+/*
+ * OWNERSHIP PROOFS
+ */
+
+// Very basic Schnorr proof (generation)
+Proof PrsonaClient::generate_ownership_proof() const
 {
     Proof retval;
-
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
     }
 
+    std::stringstream oracleInput;
+    
+    Scalar r;
+    r.set_random();
+
+    Curvepoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey;
+    Curvepoint u = currentFreshGenerator * r;
+    oracleInput << currentFreshGenerator << shortTermPublicKey << u;
+
+    Scalar c = oracle(oracleInput.str());
+    Scalar z = r.curveAdd(c.curveMult(longTermPrivateKey));
+
     retval.basic = "PROOF";
+    retval.initParts.push_back(u);
+    retval.responseParts.push_back(z);
+
     return retval;
 }
 
-bool PrsonaClient::verify_generator_proof(const Proof& pi, const Curvepoint& generator) const
+// Very basic Schnorr proof (verification)
+bool PrsonaClient::verify_ownership_proof(
+    const Proof& pi, const Curvepoint& shortTermPublicKey) const
+{
+    if (!CLIENT_IS_MALICIOUS)
+        return pi.basic == "PROOF";
+
+    Curvepoint u = pi.initParts[0];
+
+    std::stringstream oracleInput;
+    oracleInput << currentFreshGenerator << shortTermPublicKey << u;
+    Scalar c = oracle(oracleInput.str());
+
+    Scalar z = pi.responseParts[0];
+
+    return (currentFreshGenerator * z) == (shortTermPublicKey * c + u);
+}
+
+/*
+ * PROOF VERIFICATION
+ */
+
+bool PrsonaClient::verify_score_proof(const Proof& pi) const
+{
+    if (!SERVER_IS_MALICIOUS)
+        return pi.basic == "PROOF";
+
+    return pi.basic == "PROOF";
+}
+
+bool PrsonaClient::verify_generator_proof(
+    const Proof& pi, const Curvepoint& generator) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaClient::verify_default_tally_proof(const Proof& pi, const EGCiphertext& score) const
+bool PrsonaClient::verify_default_tally_proof(
+    const Proof& pi, const EGCiphertext& score) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaClient::verify_valid_tally_proof(const Proof& pi, const EGCiphertext& score) const
+bool PrsonaClient::verify_valid_tally_proof(
+    const Proof& pi, const EGCiphertext& score) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaClient::verify_default_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
+bool PrsonaClient::verify_default_votes_proof(
+    const Proof& pi, const std::vector<CurveBipoint>& votes) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaClient::verify_valid_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
+bool PrsonaClient::verify_valid_votes_proof(
+    const Proof& pi, const std::vector<CurveBipoint>& votes) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-Proof PrsonaClient::generate_vote_proof(const std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote) const
+/*
+ * PROOF GENERATION
+ */
+
+Proof PrsonaClient::generate_vote_proof(
+    const std::vector<CurveBipoint>& encryptedVotes,
+    const std::vector<Scalar>& vote) const
 {
     Proof retval;
 
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -419,11 +464,3 @@ Proof PrsonaClient::generate_vote_proof(const std::vector<CurveBipoint>& encrypt
     retval.basic = "PROOF";
     return retval;
 }
-
-bool PrsonaClient::verify_score_proof(const Proof& pi) const
-{
-    if (!malicious_server)
-        return pi.basic == "PROOF";
-
-    return pi.basic == "PROOF";
-}

+ 61 - 29
prsona/src/main.cpp

@@ -13,7 +13,18 @@
 
 using namespace std;
 
-// int argparse(int argc, char *argv[], size_t &numServers, size_t &numClients, size_t &numRounds, size_t &numVotes, bool &maliciousServers, bool &maliciousUsers, string &seedStr) 
+const int MAX_ALLOWED_VOTE = 2;
+
+// int argparse(
+//     int argc,
+//     char *argv[],
+//     size_t &numServers,
+//     size_t &numClients,
+//     size_t &numRounds,
+//     size_t &numVotes,
+//     bool &maliciousServers,
+//     bool &maliciousUsers,
+//     string &seedStr) 
 // {
 //     string config_file;
 
@@ -31,8 +42,10 @@ using namespace std;
 //     // config file
 //     po::options_description config("Configuration");
 //     config.add_options()
-//         ("malicious-servers,M", "presence of this flag indicates servers will operate in malicious model")
-//         ("malicious-users,U", "presence of this flag indicates users will operate in malicious model")
+//         ("malicious-servers,M",
+//                "presence of this flag indicates servers will operate in malicious model")
+//         ("malicious-users,U",
+//                "presence of this flag indicates users will operate in malicious model")
 //         ("seed", po::value<string>(&seedStr)->default_value("default"),
 //             "the random seed to use for this test")
 //         ;
@@ -98,14 +111,28 @@ using namespace std;
 //     return 0;
 // }
 
-double epoch(default_random_engine& generator, PrsonaServerEntity& servers, vector<PrsonaClient>& users, size_t numVotes)
+// Initialize the classes we use
+void initialize_prsona_classes()
+{
+    Scalar::init();
+    Curvepoint elGamalBlindGenerator = PrsonaServer::init();
+    PrsonaClient::init(elGamalBlindGenerator);
+}
+
+// Do an epoch (including votes, etc.), and return the timing to print out
+double epoch(
+    default_random_engine& generator,
+    PrsonaServerEntity& servers,
+    vector<PrsonaClient>& users,
+    size_t numVotes)
 {
     Proof unused;
-    uniform_int_distribution<int> voteDistribution(0, 3);
+    uniform_int_distribution<int> voteDistribution(0, MAX_ALLOWED_VOTE);
     size_t numUsers = users.size();
 
     for (size_t i = 0; i < numUsers; i++)
     {
+        // Make the correct number of new votes, but shuffle where they go
         vector<Scalar> votes;
         vector<bool> replace;
         for (size_t j = 0; j < numUsers; j++)
@@ -113,44 +140,49 @@ double epoch(default_random_engine& generator, PrsonaServerEntity& servers, vect
             votes.push_back(Scalar(voteDistribution(generator)));
             replace.push_back(j < numVotes);
         }
-
         shuffle(replace.begin(), replace.end(), generator);
 
-        vector<CurveBipoint> encryptedVotes;
+        // Make the actual votes to give to the servers
         Proof pi;
         Curvepoint shortTermPublicKey = users[i].get_short_term_public_key(pi);
-        encryptedVotes = servers.get_current_votes_by(pi, shortTermPublicKey);
-        users[i].receive_encrypted_votes(pi, encryptedVotes, false);
-        users[i].make_votes(pi, encryptedVotes, votes, replace);
+        vector<CurveBipoint> encryptedVotes = users[i].make_votes(
+                                                pi, votes, replace);
 
-        servers.receive_vote(pi, encryptedVotes, users[i].get_short_term_public_key(unused));
+        // Give the servers these new votes
+        servers.receive_vote(pi, encryptedVotes, shortTermPublicKey);
     }
 
-    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
-    servers.epoch();
-    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    // Do the epoch server calculations
+    chrono::high_resolution_clock::time_point t0 =
+        chrono::high_resolution_clock::now();
+    servers.epoch(unused);
+    chrono::high_resolution_clock::time_point t1 =
+        chrono::high_resolution_clock::now();
     
+    // Transmit the results of the epoch to each user
     for (size_t i = 0; i < numUsers; i++)
-        servers.transmit_score(users[i]);
-
-    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+        servers.transmit_updates(users[i]);
 
+    // Return the timing of the epoch server calculations
+    chrono::duration<double> time_span =
+        chrono::duration_cast<chrono::duration<double>>(t1 - t0);
     return time_span.count();
 }
 
 int main(int argc, char *argv[])
 {
-    Scalar::init();
+    initialize_prsona_classes();
 
+    // Defaults
     size_t numServers = 2;
     size_t numUsers = 5;
     size_t numRounds = 3;
     size_t numVotesPerRound = 3;
     bool maliciousServers = false;
     bool maliciousUsers = false;
-    
     string seedStr = "seed";
 
+    // Potentially accept command line inputs
     if (argc > 1)
         numServers = atoi(argv[1]);
     if (argc > 2)
@@ -164,35 +196,35 @@ int main(int argc, char *argv[])
     cout << numServers << " PRSONA servers" << endl;
     cout << numUsers << " participants (voters/votees)" << endl;
     cout << numRounds << " epochs" << endl;
-    cout << numVotesPerRound << " new (random) votes by each user in each epoch" << endl;
+    cout << numVotesPerRound << " new (random) votes by each user per epoch"
+        << endl;
 
+    // Set malicious flags where necessary
     if (maliciousServers)
     {
-        PrsonaServer::set_malicious_server();
-        PrsonaClient::set_malicious_server();
+        PrsonaServer::set_server_malicious();
+        PrsonaClient::set_server_malicious();
     }
-
     if (maliciousUsers)
     {
-        PrsonaServer::set_malicious_client();
-        PrsonaClient::set_malicious_client();
+        PrsonaServer::set_client_malicious();
+        PrsonaClient::set_client_malicious();
     }
 
+    // Entities we operate with
     PrsonaServerEntity servers(numServers);
-
     BGNPublicKey bgnPublicKey = servers.get_bgn_public_key();
 
-    Curvepoint EGBlindGenerator = servers.get_blinding_generator();
-
     cout << "Initialization: adding users to system" << endl;
     vector<PrsonaClient> users;
     for (size_t i = 0; i < numUsers; i++)
     {
-        PrsonaClient currUser(bgnPublicKey, EGBlindGenerator);
+        PrsonaClient currUser(bgnPublicKey, &servers);
         servers.add_new_client(currUser);
         users.push_back(currUser);
     }
 
+    // Seeded randomness for random votes used in epoch
     seed_seq seed(seedStr.begin(), seedStr.end());
     default_random_engine generator(seed);
 

+ 42 - 0
prsona/src/proof.cpp

@@ -0,0 +1,42 @@
+#include "proof.hpp"
+
+/* Altered from answer at
+ * https://stackoverflow.com/questions/51144505/generate-sha-3-hash-in-c-using-openssl-library
+ */
+
+// Convert the bytes to a single integer, then make that a Scalar
+Scalar bytes_to_scalar(const std::vector<uint8_t>& bytes)
+{
+    std::stringstream stream;
+    for (uint8_t b : bytes)
+    {
+        stream << std::setw(2)
+            << std::setfill('0')
+            << std::hex
+            << static_cast<int>(b);
+    }
+    mpz_class value;
+    value.set_str(stream.str(), 16);
+
+    return Scalar(value);
+}
+
+// Random Oracle (i.e. SHA3_256)
+Scalar oracle(const std::string& input)
+{
+    uint32_t digest_length = SHA256_DIGEST_LENGTH;
+    const EVP_MD* algorithm = EVP_sha3_256();
+    uint8_t* digest = static_cast<uint8_t*>(OPENSSL_malloc(digest_length));
+    
+    EVP_MD_CTX* context = EVP_MD_CTX_new();
+    EVP_DigestInit_ex(context, algorithm, NULL);
+    EVP_DigestUpdate(context, input.c_str(), input.size());
+    EVP_DigestFinal_ex(context, digest, &digest_length);
+    EVP_MD_CTX_destroy(context);
+
+    std::vector<uint8_t> digestBytes(digest, digest + digest_length);
+    Scalar output = bytes_to_scalar(digestBytes);
+    OPENSSL_free(digest);
+
+    return output;
+}

+ 363 - 147
prsona/src/server.cpp

@@ -4,44 +4,79 @@
 
 extern const curvepoint_fp_t bn_curvegen;
 extern const scalar_t bn_n;
-
-// This needs to be here so it's "defined", but it doesn't always seem to actually, uh, execute, so you do it over in the constructor
-Curvepoint PrsonaServer::elGamalGenerator = Curvepoint();
-Scalar PrsonaServer::scalarN = Scalar();
-Scalar PrsonaServer::defaultTally = Scalar();
-Scalar PrsonaServer::defaultVote = Scalar();
-bool PrsonaServer::malicious_server = false;
-bool PrsonaServer::malicious_client = false;
-
+const int MAX_ALLOWED_VOTE = 2;
+
+/* These lines need to be here so these static variables are defined,
+ * but in C++ putting code here doesn't actually execute
+ * (or at least, with g++, whenever it would execute is not at a useful time)
+ * so we have an init() function to actually put the correct values in them. */
+Curvepoint PrsonaServer::EL_GAMAL_GENERATOR = Curvepoint();
+Curvepoint PrsonaServer::EL_GAMAL_BLIND_GENERATOR = Curvepoint();
+Scalar PrsonaServer::SCALAR_N = Scalar();
+Scalar PrsonaServer::DEFAULT_TALLY = Scalar();
+Scalar PrsonaServer::DEFAULT_VOTE = Scalar();
+bool PrsonaServer::SERVER_IS_MALICIOUS = false;
+bool PrsonaServer::CLIENT_IS_MALICIOUS = false;
+
+/********************
+ * PUBLIC FUNCTIONS *
+ ********************/
+
+/*
+ * CONSTRUCTORS
+ */
+
+// Used to generate the first server; instantiates BGN for the first time
 PrsonaServer::PrsonaServer()
 {
-    elGamalGenerator = Curvepoint(bn_curvegen);
-    scalarN = Scalar(bn_n);
-    defaultTally = Scalar(1);
-    defaultVote = Scalar(0);
+    currentSeed.set_random();
+}
+
+// Used for all other servers, so they have the same BGN parameters
+PrsonaServer::PrsonaServer(const BGN& other_bgn)
+: bgn_system(other_bgn)
+{
+    currentSeed.set_random();
+}
 
+/*
+ * SETUP FUNCTIONS
+ */
+
+// Must be called once before any usage of this class
+Curvepoint PrsonaServer::init()
+{
     Scalar lambda;
     lambda.set_random();
 
-    elGamalBlindGenerator = elGamalGenerator * lambda;
+    EL_GAMAL_GENERATOR = Curvepoint(bn_curvegen);
+    EL_GAMAL_BLIND_GENERATOR = EL_GAMAL_GENERATOR * lambda;
+    SCALAR_N = Scalar(bn_n);
+    DEFAULT_TALLY = Scalar(1);
+    DEFAULT_VOTE = Scalar(1);
 
-    currentSeed.set_random();
+    return EL_GAMAL_BLIND_GENERATOR;
 }
 
-PrsonaServer::PrsonaServer(const BGN& other_bgn, const Curvepoint& other_blind_gen)
-: bgn_system(other_bgn), elGamalBlindGenerator(other_blind_gen)
+// Call this (once) if using malicious-security servers
+void PrsonaServer::set_server_malicious()
 {
-    currentSeed.set_random();
+    SERVER_IS_MALICIOUS = true;
 }
 
-void PrsonaServer::set_malicious_server()
+// Call this (once) if using malicious-security clients
+void PrsonaServer::set_client_malicious()
 {
-    malicious_server = true;
+    CLIENT_IS_MALICIOUS = true;
 }
 
-void PrsonaServer::set_malicious_client()
+/*
+ * BASIC PUBLIC SYSTEM INFO GETTERS
+ */
+
+Curvepoint PrsonaServer::get_blinding_generator()
 {
-    malicious_client = true;
+    return EL_GAMAL_BLIND_GENERATOR;
 }
 
 BGNPublicKey PrsonaServer::get_bgn_public_key() const
@@ -49,37 +84,71 @@ BGNPublicKey PrsonaServer::get_bgn_public_key() const
     return bgn_system.get_public_key();
 }
 
-Curvepoint PrsonaServer::get_blinding_generator() const
-{
-    return elGamalBlindGenerator;
-}
+/*
+ * FRESH GENERATOR CALCULATION
+ */
 
-Curvepoint PrsonaServer::add_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const
+// To calculate the current epoch's generator, start from the base generator,
+// then have every server call this function on it iteratively (in any order).
+Curvepoint PrsonaServer::add_curr_seed_to_generator(
+    const Curvepoint& currGenerator) const
 {
-    pi = generate_valid_fresh_generator_proof(pi);
-
     return currGenerator * currentSeed;
 }
 
-Curvepoint PrsonaServer::add_next_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const
+// To calculate the next epoch's generator, start from the base generator,
+// then have every server call this function on it iteratively (in any order).
+Curvepoint PrsonaServer::add_next_seed_to_generator(
+    const Curvepoint& currGenerator) const
 {
-    pi = generate_valid_fresh_generator_proof(pi);
-
     return currGenerator * nextSeed;
 }
 
-std::vector<CurveBipoint> PrsonaServer::get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const
+/*
+ * ENCRYPTED DATA GETTERS
+ */
+
+/* Call this in order to get the current encrypted votes cast by a given user
+ * (who is identified by their short term public key).
+ * In practice, this is intended for clients,
+ * who need to know their current votes in order to rerandomize them. */
+std::vector<CurveBipoint> PrsonaServer::get_current_votes_by(
+    Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
     std::vector<CurveBipoint> retval;
     size_t voteSubmitter = binary_search(shortTermPublicKey);
     retval = voteMatrix[voteSubmitter];
 
     pi = generate_votes_valid_proof(retval, shortTermPublicKey);
+    return retval;
+}
+
+/* Call this in order to get the current encrypted tally of a given user
+ * (who is identified by their short term public key).
+ * In practice, this is intended for clients, so that the servers vouch
+ * for their ciphertexts being valid as part of their reputation proofs. */
+EGCiphertext PrsonaServer::get_current_tally(
+    Proof& pi, const Curvepoint& shortTermPublicKey) const
+{
+    EGCiphertext retval;
+    size_t tallyOwner = binary_search(shortTermPublicKey);
+    retval = currentUserEncryptedTallies[tallyOwner];
     
+    pi = currentTallyProofs[tallyOwner];
     return retval;
 }
 
-void PrsonaServer::add_new_client(const Proof& proofOfValidKey, Proof& proofOfValidAddition, const Curvepoint& shortTermPublicKey)
+/*
+ * CLIENT INTERACTIONS
+ */
+
+/* Add a new client (who is identified only by their short term public key)
+ * One server will do this, then ask all other servers to import their
+ * (proven) exported data. */
+void PrsonaServer::add_new_client(
+    const Proof& proofOfValidKey,
+    Proof& proofOfValidAddition,
+    const Curvepoint& shortTermPublicKey)
 {
     if (!verify_valid_key_proof(proofOfValidKey, shortTermPublicKey))
     {
@@ -89,12 +158,27 @@ void PrsonaServer::add_new_client(const Proof& proofOfValidKey, Proof& proofOfVa
 
     currentPseudonyms.push_back(shortTermPublicKey);
 
-    TwistBipoint newTalliedVote;
-    bgn_system.encrypt(newTalliedVote, defaultTally);
-    previousVoteTally.push_back(newTalliedVote);
-
-    CurveBipoint encryptedDefaultVote;
-    bgn_system.encrypt(encryptedDefaultVote, defaultVote);
+    // The first epoch's score for a new user will be low,
+    // but will typically converge on an average score quickly
+    TwistBipoint encryptedDefaultTally;
+    bgn_system.encrypt(encryptedDefaultTally, DEFAULT_TALLY);
+    previousVoteTallies.push_back(encryptedDefaultTally);
+
+    Scalar mask;
+    mask.set_random();
+    EGCiphertext newUserEncryptedTally;
+    newUserEncryptedTally.mask = shortTermPublicKey * mask;
+    newUserEncryptedTally.encryptedMessage =
+        currentFreshGenerator * mask +
+        get_blinding_generator() * DEFAULT_TALLY;
+    currentUserEncryptedTallies.push_back(newUserEncryptedTally);
+    currentTallyProofs.push_back(
+        generate_valid_default_tally_proof(newUserEncryptedTally, mask));
+
+    // Users are defaulted to casting a neutral vote for others.
+    CurveBipoint encryptedDefaultVote, encryptedSelfVote;
+    bgn_system.encrypt(encryptedDefaultVote, DEFAULT_VOTE);
+    bgn_system.encrypt(encryptedSelfVote, Scalar(MAX_ALLOWED_VOTE));
     std::vector<CurveBipoint> newRow;
     for (size_t i = 0; i < voteMatrix.size(); i++)
     {
@@ -104,17 +188,21 @@ void PrsonaServer::add_new_client(const Proof& proofOfValidKey, Proof& proofOfVa
         encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
         newRow.push_back(encryptedDefaultVote);
     }
-
-    encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
-    newRow.push_back(encryptedDefaultVote);
+    // Because we are adding the new user to the end (and then sorting it),
+    // this last element (bottom right corner) is always the self vote.
+    newRow.push_back(encryptedSelfVote);
     voteMatrix.push_back(newRow);
 
-    order_data();
+    order_data(proofOfValidAddition);
 
     proofOfValidAddition = generate_proof_of_added_user(shortTermPublicKey);
 }
 
-void PrsonaServer::receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
+// Receive a new vote row from a user (identified by short term public key).
+void PrsonaServer::receive_vote(
+    const Proof& pi,
+    const std::vector<CurveBipoint>& votes,
+    const Curvepoint& shortTermPublicKey)
 {
     if (!verify_vote_proof(pi, votes, shortTermPublicKey))
     {
@@ -126,12 +214,34 @@ void PrsonaServer::receive_vote(const Proof& pi, const std::vector<CurveBipoint>
     voteMatrix[voteSubmitter] = votes;
 }
 
+/*********************
+ * PRIVATE FUNCTIONS *
+ *********************/
+
+/*
+ * CONSTRUCTOR HELPERS
+ */
+
 const BGN& PrsonaServer::get_bgn_details() const
 {
     return bgn_system;
 }
 
-std::vector<Scalar> PrsonaServer::tally_scores(Proof& pi)
+void PrsonaServer::initialize_fresh_generator(const Curvepoint& firstGenerator)
+{
+    currentFreshGenerator = firstGenerator;
+}
+
+/*
+ * SCORE TALLYING
+ */
+
+/* Calculate scores homomorphically (as an individual server would normally)
+ * and then decrypt them (which the servers would normally work together to do).
+ *
+ * Note that since these calculations are just for us, we don't need to do any
+ * expensive rerandomizations of intermediate values. */
+std::vector<Scalar> PrsonaServer::tally_scores(std::vector<Proof>& tallyProofs)
 {
     std::vector<Quadripoint> BGNEncryptedTallies;
     std::vector<Scalar> decryptedTallies;
@@ -139,122 +249,179 @@ std::vector<Scalar> PrsonaServer::tally_scores(Proof& pi)
     {
         std::vector<Quadripoint> weightedVotes;
 
-        for (size_t j = 0; j < previousVoteTally.size(); j++)
+        // ZIP
+        for (size_t j = 0; j < previousVoteTallies.size(); j++)
         {
-            Quadripoint curr = bgn_system.homomorphic_multiplication_no_rerandomize(voteMatrix[j][i], previousVoteTally[j]);
+            Quadripoint curr =
+                bgn_system.homomorphic_multiplication_no_rerandomize(
+                    voteMatrix[j][i], previousVoteTallies[j]);
+
             weightedVotes.push_back(curr);
         }
 
+        // FOLDL
         Quadripoint currEncryptedTally = weightedVotes[0];
         for (size_t j = 1; j < weightedVotes.size(); j++)
-            currEncryptedTally = bgn_system.homomorphic_addition_no_rerandomize(currEncryptedTally, weightedVotes[j]);
+        {
+            currEncryptedTally =
+                bgn_system.homomorphic_addition_no_rerandomize(
+                    currEncryptedTally, weightedVotes[j]);
+        }
 
+        // DECRYPT
         decryptedTallies.push_back(bgn_system.decrypt(currEncryptedTally));
+        tallyProofs.push_back(
+            generate_proof_of_correct_tally(
+                currEncryptedTally, decryptedTallies[i]));
     }
 
-    pi = generate_proof_of_correct_tally(BGNEncryptedTallies, decryptedTallies);
-
     return decryptedTallies;
 }
 
+/* Calculate what the maximum possible score this round was (that is,
+ * given the current user weights, what was the highest possible score?).
+ *
+ * As with individual scores, this also does the decryption that servers
+ * would ordinarily work together to form. */
 Scalar PrsonaServer::get_max_possible_score(Proof& pi)
 {
-    TwistBipoint currEncryptedVal = previousVoteTally[0];
-    for (size_t i = 1; i < previousVoteTally.size(); i++)
-        currEncryptedVal = bgn_system.homomorphic_addition_no_rerandomize(currEncryptedVal, previousVoteTally[i]);
+    // FOLDL
+    TwistBipoint currEncryptedVal = previousVoteTallies[0];
+    for (size_t i = 1; i < previousVoteTallies.size(); i++)
+    {
+        currEncryptedVal =
+            bgn_system.homomorphic_addition_no_rerandomize(
+                currEncryptedVal, previousVoteTallies[i]);
+    }
 
+    // DECRYPT
     Scalar retval = bgn_system.decrypt(currEncryptedVal);
-    pi = generate_proof_of_correct_sum(currEncryptedVal, retval);
 
+    pi = generate_proof_of_correct_sum(currEncryptedVal, retval);
     return retval;
 }
 
-void PrsonaServer::export_updates(std::vector<TwistBipoint>& otherPreviousVoteTally,
-    std::vector<Curvepoint>& otherCurrentPseudonyms, std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
-{
-    otherPreviousVoteTally = previousVoteTally;
-    otherCurrentPseudonyms = currentPseudonyms;
-    otherVoteMatrix = voteMatrix;
-}
+/*
+ * EPOCH ROUNDS
+ */
 
-void PrsonaServer::import_updates(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally,
-    const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix)
-{
-    if (!verify_update_proof(pi, otherPreviousVoteTally, otherCurrentPseudonyms, otherVoteMatrix))
-    {
-        std::cerr << "Could not verify valid update." << std::endl;
-        return;
-    }
-
-    previousVoteTally = otherPreviousVoteTally;
-    currentPseudonyms = otherCurrentPseudonyms;
-    voteMatrix = otherVoteMatrix;
-}
-
-void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies, std::vector<Scalar>& encryptedTallyMasks)
+// The first round, going from A_0 to A_0.5
+void PrsonaServer::build_up_midway_pseudonyms(
+    Proof& pi, Curvepoint& nextGenerator)
 {
     nextSeed.set_random();
     nextGenerator = nextGenerator * nextSeed;
 
-    for (size_t i = 0; i < currentPseudonyms.size(); i++)
-    {
-        Scalar currMask;
-        currMask.set_random();
+    currentUserEncryptedTallies.clear();
+    currentTallyProofs.clear();
 
-        encryptedTallyMasks[i] = encryptedTallyMasks[i].curveAdd(currMask);
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
         currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
-    }   
-        
-    std::vector<size_t> shuffleOrder = order_data();
-    rerandomize_vote_matrix();
-
-    std::vector<Scalar> reorderedTallies;
-    for (size_t i = 0; i < shuffleOrder.size(); i++)
-        reorderedTallies.push_back(decryptedTallies[shuffleOrder[i]]);
-    decryptedTallies = reorderedTallies;
 
-    pi = generate_proof_of_shuffle(shuffleOrder);
+    rerandomize_data();
+    order_data(pi);
 }
 
-void PrsonaServer::epoch_part_two(Proof& pi, const Curvepoint& nextGenerator, std::vector<EGCiphertext>& encryptedTallies, std::vector<Scalar>& encryptedTallyMasks)
+// In between these rounds, scores are tallied, decrypted,
+// and encrypted to fresh user pseudonyms (possible through weird math)
+
+// The second round, going from A_0.5 to A_1
+void PrsonaServer::break_down_midway_pseudonyms(
+    Proof& pi, const Curvepoint& nextGenerator)
 {
     Scalar inverseSeed = currentSeed.curveInverse();
 
     for (size_t i = 0; i < currentPseudonyms.size(); i++)
     {
-        Scalar rerandomizer;
-        rerandomizer.set_random();
-
         currentPseudonyms[i] = currentPseudonyms[i] * inverseSeed;
-        encryptedTallies[i].mask = encryptedTallies[i].mask * inverseSeed;
-
-        encryptedTallies[i].mask = encryptedTallies[i].mask + currentPseudonyms[i] * rerandomizer;
-        encryptedTallies[i].encryptedMessage = encryptedTallies[i].encryptedMessage + nextGenerator * rerandomizer;
-
-        encryptedTallyMasks[i] = encryptedTallyMasks[i].curveAdd(rerandomizer);
+        currentUserEncryptedTallies[i].mask =
+            currentUserEncryptedTallies[i].mask * inverseSeed;
     }
 
-    std::vector<size_t> shuffleOrder = order_data();
-    rerandomize_vote_matrix();
+    currentSeed = nextSeed;
+    currentFreshGenerator = nextGenerator;
+
+    rerandomize_data();
+    order_data(pi);
+}
 
-    std::vector<Scalar> reorderedMasks;
-    std::vector<EGCiphertext> reorderedTallies;
-    for (size_t i = 0; i < shuffleOrder.size(); i++)
+/*
+ * DATA MAINTENANCE
+ */
+
+void PrsonaServer::import_updates(
+    const Proof& pi,
+    const std::vector<TwistBipoint>& otherPreviousVoteTallies,
+    const std::vector<Curvepoint>& otherCurrentPseudonyms,
+    const std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
+    const std::vector<Proof>& otherCurrentTallyProofs,
+    const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix)
+{
+    if (!verify_update_proof(pi))
     {
-        reorderedMasks.push_back(encryptedTallyMasks[shuffleOrder[i]]);
-        reorderedTallies.push_back(encryptedTallies[shuffleOrder[i]]);
+        std::cerr << "Could not verify valid update." << std::endl;
+        return;
     }
-    encryptedTallyMasks = reorderedMasks;
-    encryptedTallies = reorderedTallies;
 
-    pi = generate_proof_of_shuffle(shuffleOrder);
+    previousVoteTallies = otherPreviousVoteTallies;
+    currentPseudonyms = otherCurrentPseudonyms;
+    currentUserEncryptedTallies = otherCurrentUserEncryptedTallies;
+    currentTallyProofs = otherCurrentTallyProofs;
+    voteMatrix = otherVoteMatrix;
+}
 
-    currentSeed = nextSeed;
+void PrsonaServer::export_updates(
+    std::vector<TwistBipoint>& otherPreviousVoteTallies,
+    std::vector<Curvepoint>& otherCurrentPseudonyms,
+    std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
+    std::vector<Proof>& otherCurrentTallyProofs,
+    std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
+{
+    otherPreviousVoteTallies = previousVoteTallies;
+    otherCurrentPseudonyms = currentPseudonyms;
+    otherCurrentUserEncryptedTallies = currentUserEncryptedTallies;
+    otherCurrentTallyProofs = currentTallyProofs;
+    otherVoteMatrix = voteMatrix;
+}
+
+/*
+ * DATA SAFEKEEPING
+ */
+
+// Everything needs to be rerandomized during epoch rounds
+// NOTE: this may need to add something about proofs later?
+void PrsonaServer::rerandomize_data()
+{
+    for (size_t i = 0; i < voteMatrix.size(); i++)
+    {
+        for (size_t j = 0; j < voteMatrix[0].size(); j++)
+            voteMatrix[i][j] = bgn_system.rerandomize(voteMatrix[i][j]);
+
+        bgn_system.rerandomize(previousVoteTallies[i]);
+        if (!currentUserEncryptedTallies.empty())
+        {
+            Scalar rerandomizer;
+            rerandomizer.set_random();
+
+            currentUserEncryptedTallies[i].mask =
+                currentUserEncryptedTallies[i].mask +
+                currentPseudonyms[i] * rerandomizer;
+            currentUserEncryptedTallies[i].encryptedMessage =
+                currentUserEncryptedTallies[i].encryptedMessage +
+                currentFreshGenerator * rerandomizer;
+        }
+    }
 }
 
-std::vector<size_t> PrsonaServer::order_data()
+/* This is what powers the "shuffle"; really, as pseudonyms get updated,
+ * the pseudonyms are no longer in the order prescribed by operator<().
+ * So, we put them (and everything else) back into that order,
+ * effectively shuffling them (and making lookups easier later on). */
+std::vector<size_t> PrsonaServer::order_data(Proof& pi)
 {
     std::vector<size_t> retval;
+
+    // SortingType's index member allows us to replicate the "sort" across
     std::vector<SortingType> sortTracker;
     for (size_t i = 0; i < currentPseudonyms.size(); i++)
     {
@@ -265,46 +432,59 @@ std::vector<size_t> PrsonaServer::order_data()
 
         sortTracker.push_back(curr);
     }
-
     std::sort(sortTracker.begin(), sortTracker.end());
 
+    // Order all other data in the same way, for consistency
     std::vector<Curvepoint> newPseudonyms;
     std::vector<TwistBipoint> newVoteTallies;
+    std::vector<EGCiphertext> newUserEncryptedTallies;
+    std::vector<Proof> newTallyProofs;
     std::vector<std::vector<CurveBipoint>> newVoteMatrix;
 
     for (size_t i = 0; i < sortTracker.size(); i++)
     {
         newPseudonyms.push_back(sortTracker[i].pseudonym);
-        newVoteTallies.push_back(previousVoteTally[sortTracker[i].index]);
+        newVoteTallies.push_back(previousVoteTallies[sortTracker[i].index]);
+        
+        if (!currentUserEncryptedTallies.empty())
+        {
+            newUserEncryptedTallies.push_back(
+                currentUserEncryptedTallies[sortTracker[i].index]);
+        }
+        if (!currentTallyProofs.empty())
+        {
+            newTallyProofs.push_back(
+                currentTallyProofs[sortTracker[i].index]);
+        }
 
         std::vector<CurveBipoint> currNewRow;
         for (size_t j = 0; j < currentPseudonyms.size(); j++)
         {
-            currNewRow.push_back(voteMatrix[sortTracker[i].index][sortTracker[j].index]);
+            currNewRow.push_back(
+                voteMatrix[sortTracker[i].index][sortTracker[j].index]);
         }
         newVoteMatrix.push_back(currNewRow);
 
         retval.push_back(sortTracker[i].index);
     }
 
+    previousVoteTallies = newVoteTallies;
     currentPseudonyms = newPseudonyms;
-    previousVoteTally = newVoteTallies;
+    currentUserEncryptedTallies = newUserEncryptedTallies;
+    currentTallyProofs = newTallyProofs;
     voteMatrix = newVoteMatrix;
 
+    pi = generate_proof_of_shuffle(retval);
     return retval;
 }
 
-void PrsonaServer::rerandomize_vote_matrix()
-{
-    for (size_t i = 0; i < voteMatrix.size(); i++)
-    {
-        for (size_t j = 0; j < voteMatrix[0].size(); j++)
-        {
-            voteMatrix[i][j] = bgn_system.rerandomize(voteMatrix[i][j]);
-        }
-    }
-}
+/*
+ * BINARY SEARCH
+ */
 
+/* Completely normal binary search
+ * There might be a standard function for this in <algorithms>?
+ * But it returns an iterator, not a size_t, so less useful. */
 size_t PrsonaServer::binary_search(const Curvepoint& index) const
 {
     size_t lo, hi;
@@ -324,35 +504,65 @@ size_t PrsonaServer::binary_search(const Curvepoint& index) const
     return lo;
 }
 
-bool PrsonaServer::verify_valid_key_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
+/*
+ * PROOF VERIFICATION
+ */
+
+bool PrsonaServer::verify_valid_key_proof(
+    const Proof& pi,
+    const Curvepoint& shortTermPublicKey) const
 {
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaServer::verify_vote_proof(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
+bool PrsonaServer::verify_vote_proof(
+    const Proof& pi,
+    const std::vector<CurveBipoint>& votes,
+    const Curvepoint& shortTermPublicKey) const
 {
-    if (!malicious_client)
+    if (!CLIENT_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-bool PrsonaServer::verify_update_proof(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally, const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
+bool PrsonaServer::verify_update_proof(
+    const Proof& pi) const
 {
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
         return pi.basic == "PROOF";
 
     return pi.basic == "PROOF";
 }
 
-Proof PrsonaServer::generate_valid_fresh_generator_proof(const Proof& oldProof) const
+/*
+ * PROOF GENERATION
+ */
+
+Proof PrsonaServer::generate_valid_default_tally_proof(
+    const EGCiphertext& newUserEncryptedTally, const Scalar& mask) const
+{
+    Proof retval;
+
+    if (!SERVER_IS_MALICIOUS)
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
+
+    retval.basic = "PROOF";
+    return retval;
+}
+
+Proof PrsonaServer::generate_valid_fresh_generator_proof(
+    const Proof& oldProof) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -362,11 +572,12 @@ Proof PrsonaServer::generate_valid_fresh_generator_proof(const Proof& oldProof)
     return retval;
 }
 
-Proof PrsonaServer::generate_votes_valid_proof(const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
+Proof PrsonaServer::generate_votes_valid_proof(
+    const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -376,11 +587,12 @@ Proof PrsonaServer::generate_votes_valid_proof(const std::vector<CurveBipoint>&
     return retval;
 }
 
-Proof PrsonaServer::generate_proof_of_added_user(const Curvepoint& shortTermPublicKey) const
+Proof PrsonaServer::generate_proof_of_added_user(
+    const Curvepoint& shortTermPublicKey) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -394,7 +606,7 @@ Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -404,11 +616,13 @@ Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
     return retval;
 }
 
-Proof PrsonaServer::generate_proof_of_correct_tally(const std::vector<Quadripoint>& BGNEncryptedTallies, const std::vector<Scalar>& decryptedTallies) const
+Proof PrsonaServer::generate_proof_of_correct_tally(
+    const Quadripoint& BGNEncryptedTally,
+    const Scalar& decryptedTally) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -418,11 +632,12 @@ Proof PrsonaServer::generate_proof_of_correct_tally(const std::vector<Quadripoin
     return retval;
 }
 
-Proof PrsonaServer::generate_proof_of_correct_sum(const TwistBipoint& BGNEncryptedSum, const Scalar& decryptedSum) const
+Proof PrsonaServer::generate_proof_of_correct_sum(
+    const TwistBipoint& BGNEncryptedSum, const Scalar& decryptedSum) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;
@@ -432,11 +647,12 @@ Proof PrsonaServer::generate_proof_of_correct_sum(const TwistBipoint& BGNEncrypt
     return retval;
 }
 
-Proof PrsonaServer::generate_proof_of_shuffle(const std::vector<size_t>& shuffle_order) const
+Proof PrsonaServer::generate_proof_of_shuffle(
+    const std::vector<size_t>& shuffle_order) const
 {
     Proof retval;
 
-    if (!malicious_server)
+    if (!SERVER_IS_MALICIOUS)
     {
         retval.basic = "PROOF";
         return retval;

+ 224 - 175
prsona/src/serverEntity.cpp

@@ -2,26 +2,44 @@
 
 #include "serverEntity.hpp"
 
-const int maxAllowedVote = 3;
+const int MAX_ALLOWED_VOTE = 2;
+
+/********************
+ * PUBLIC FUNCTIONS *
+ ********************/
+
+/*
+ * CONSTRUCTORS
+ */
 
 PrsonaServerEntity::PrsonaServerEntity(size_t numServers)
 {
     if (numServers < 1)
-        std::cerr << "You have to have at least 1 server. I'm making it anyways." << std::endl;
+    {
+        std::cerr << "You have to have at least 1 server. "
+            << "I'm making it anyways." << std::endl;
+    }
 
+    // Make the first server, which makes the BGN parameters
     PrsonaServer firstServer;
     servers.push_back(firstServer);
 
+    // Make the rest of the servers, which take the BGN parameters
     const BGN& sharedBGN = firstServer.get_bgn_details();
-    Curvepoint sharedEGBlindGenerator = firstServer.get_blinding_generator();
-
     for (size_t i = 1; i < numServers; i++)
-    {
-        PrsonaServer currServer(sharedBGN, sharedEGBlindGenerator);
-        servers.push_back(currServer);
-    }
+        servers.push_back(PrsonaServer(sharedBGN));
+
+    // After all servers have made their seeds,
+    // make sure they have the initial fresh generator
+    Curvepoint firstGenerator = get_fresh_generator();
+    for (size_t i = 0; i < numServers; i++)
+        servers[i].initialize_fresh_generator(firstGenerator);
 }
 
+/*
+ * BASIC PUBLIC SYSTEM INFO GETTERS
+ */
+
 BGNPublicKey PrsonaServerEntity::get_bgn_public_key() const
 {
     return servers[0].get_bgn_public_key();
@@ -32,233 +50,264 @@ Curvepoint PrsonaServerEntity::get_blinding_generator() const
     return servers[0].get_blinding_generator();
 }
 
-Curvepoint PrsonaServerEntity::get_fresh_generator(Proof& pi) const
+Curvepoint PrsonaServerEntity::get_fresh_generator() const
 {
-    Curvepoint retval = PrsonaServer::elGamalGenerator;
+    Curvepoint retval = PrsonaServer::EL_GAMAL_GENERATOR;
     for (size_t j = 0; j < servers.size(); j++)
-        retval = servers[j].add_seed_to_generator(pi, retval);
+        retval = servers[j].add_curr_seed_to_generator(retval);
 
     return retval;
 }
 
-Scalar PrsonaServerEntity::decrypt(const CurveBipoint& input)
+/*
+ * ENCRYPTED DATA GETTERS
+ */
+
+/* Call this in order to get the current encrypted votes cast by a given user
+ * (who is identified by their short term public key).
+ * In practice, this is intended for clients,
+ * who need to know their current votes in order to rerandomize them. */
+std::vector<CurveBipoint> PrsonaServerEntity::get_current_votes_by(
+    Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
-    return servers[0].bgn_system.decrypt(input);
+    return servers[0].get_current_votes_by(pi, shortTermPublicKey);
 }
 
-std::vector<CurveBipoint> PrsonaServerEntity::get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const
+/* Call this in order to get the current encrypted tally of a given user
+ * (who is identified by their short term public key).
+ * In practice, this is intended for clients, so that the servers vouch
+ * for their ciphertexts being valid as part of their reputation proofs. */
+EGCiphertext PrsonaServerEntity::get_current_tally(
+    Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
-    return servers[0].get_current_votes_by(pi, shortTermPublicKey);
+    return servers[0].get_current_tally(pi, shortTermPublicKey);
 }
 
+/*
+ * CLIENT INTERACTIONS
+ */
+
+/* Add a new client (who is identified only by their short term public key)
+ * One server does the main work, then other servers import their (proven)
+ * exported data. */
 void PrsonaServerEntity::add_new_client(PrsonaClient& newUser)
 {
-    Proof proofOfValidGenerator, proofOfValidSTPK, proofOfCorrectAddition, proofOfDefaultTally, proofOfValidVotes;
-    Curvepoint freshGenerator = get_fresh_generator(proofOfValidGenerator);
+    Proof proofOfValidSTPK, proofOfCorrectAddition, proofOfValidVotes;
+    Curvepoint freshGenerator = get_fresh_generator();
 
-    newUser.receive_fresh_generator(proofOfValidGenerator, freshGenerator);
-    Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(proofOfValidSTPK);
+    // Users can't actually announce a short term public key
+    // if they don't know the fresh generator.
+    newUser.receive_fresh_generator(freshGenerator);
+    Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(
+                                        proofOfValidSTPK);
 
-    servers[0].add_new_client(proofOfValidSTPK, proofOfCorrectAddition, shortTermPublicKey);
+    // Do the actual work of adding the client to the first server
+    servers[0].add_new_client(
+        proofOfValidSTPK, proofOfCorrectAddition, shortTermPublicKey);
 
+    // Then, export the data to the rest of the servers
     std::vector<TwistBipoint> previousVoteTally;
     std::vector<Curvepoint> currentPseudonyms;
+    std::vector<EGCiphertext> currentUserEncryptedTallies;
+    std::vector<Proof> currentTallyProofs;
     std::vector<std::vector<CurveBipoint>> voteMatrix;
-    servers[0].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
-
+    servers[0].export_updates(
+        previousVoteTally,
+        currentPseudonyms,
+        currentUserEncryptedTallies,
+        currentTallyProofs,
+        voteMatrix);
     for (size_t j = 1; j < servers.size(); j++)
-        servers[j].import_updates(proofOfCorrectAddition, previousVoteTally, currentPseudonyms, voteMatrix);
+    {
+        servers[j].import_updates(
+            proofOfCorrectAddition,
+            previousVoteTally,
+            currentPseudonyms,
+            currentUserEncryptedTallies,
+            currentTallyProofs,
+            voteMatrix);
+    }
 
-    Scalar randomizationMask;
-    EGCiphertext defaultTally = get_default_tally(proofOfDefaultTally, shortTermPublicKey, randomizationMask);
-    newUser.receive_vote_tally(proofOfDefaultTally, defaultTally, true, randomizationMask);
-    std::vector<CurveBipoint> encryptedDefaults = servers[0].get_current_votes_by(proofOfValidVotes, shortTermPublicKey);
-    newUser.receive_encrypted_votes(proofOfValidVotes, encryptedDefaults, true);
+    // Finally, give the user the information it needs
+    // about its current tally and votes
+    transmit_updates(newUser);
 }
 
-void PrsonaServerEntity::receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
+// Receive a new vote row from a user (identified by short term public key).
+void PrsonaServerEntity::receive_vote(
+    const Proof& pi,
+    const std::vector<CurveBipoint>& votes,
+    const Curvepoint& shortTermPublicKey)
 {
     for (size_t j = 0; j < servers.size(); j++)
         servers[j].receive_vote(pi, votes, shortTermPublicKey);
 }
 
-void PrsonaServerEntity::epoch()
+// After tallying scores and new vote matrix,
+// give those to a user for the new epoch
+void PrsonaServerEntity::transmit_updates(PrsonaClient& currUser) const
 {
-    Proof pi, proofOfCorrectTally, testUserPi;
-    Curvepoint nextGenerator = PrsonaServer::elGamalGenerator;
-    std::vector<Scalar> decryptedTalliedScores = tally_scores(proofOfCorrectTally);
+    Proof proofOfValidSTPK, proofOfScore, proofOfCorrectVotes;
+    Curvepoint freshGenerator = get_fresh_generator();
+
+    // Get users the next fresh generator so they can correctly
+    // ask for their new scores and vote row
+    currUser.receive_fresh_generator(freshGenerator);
+    Curvepoint shortTermPublicKey = currUser.get_short_term_public_key(
+                                        proofOfValidSTPK);
+
+    EGCiphertext score = get_current_tally(proofOfScore, shortTermPublicKey);
+    currUser.receive_vote_tally(proofOfScore, score);
+
+    std::vector<CurveBipoint> encryptedVotes = get_current_votes_by(
+            proofOfCorrectVotes, shortTermPublicKey);
+    currUser.receive_encrypted_votes(proofOfCorrectVotes, encryptedVotes);
+}
+
+/*
+ * EPOCH
+ */
+
+// Do the epoch process
+void PrsonaServerEntity::epoch(Proof& pi)
+{
+    Curvepoint nextGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
+    
     std::vector<TwistBipoint> previousVoteTally;
     std::vector<Curvepoint> currentPseudonyms;
+    std::vector<EGCiphertext> currentUserEncryptedTallies;
+    std::vector<Proof> currentTallyProofs;
     std::vector<std::vector<CurveBipoint>> voteMatrix;
 
-    encryptedTallyMasks.clear();
-    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
-        encryptedTallyMasks.push_back(Scalar());
-
+    // go from A_0 to A_0.5
     for (size_t i = 0; i < servers.size(); i++)
     {
-        servers[i].epoch_part_one(pi, nextGenerator, decryptedTalliedScores, encryptedTallyMasks);
-        servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+        servers[i].build_up_midway_pseudonyms(pi, nextGenerator);
+        servers[i].export_updates(
+            previousVoteTally,
+            currentPseudonyms,
+            currentUserEncryptedTallies,
+            currentTallyProofs,
+            voteMatrix);
         if (i < servers.size() - 1)
-            servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
-    }
-
-    encryptedTallies.clear();
-    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
-    {
-        EGCiphertext currCiphertext;
-        encryptedTallies.push_back(currCiphertext);
-
-        servers[0].bgn_system.encrypt(previousVoteTally[i], decryptedTalliedScores[i]);
-        
-        encryptedTallies[i].mask = currentPseudonyms[i] * encryptedTallyMasks[i];
-        encryptedTallies[i].encryptedMessage = (nextGenerator * encryptedTallyMasks[i]) + (get_blinding_generator() * decryptedTalliedScores[i]);
+        {
+            servers[i + 1].import_updates(
+                pi,
+                previousVoteTally,
+                currentPseudonyms,
+                currentUserEncryptedTallies,
+                currentTallyProofs,
+                voteMatrix);
+        }
     }
 
-    pi = generate_epoch_round_one_proof(pi, proofOfCorrectTally);
-    servers[0].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+    /* Imagine that server 0 is encrypting these, then would do a ZKP that it
+     * knows a secret mask and encrypted the correct value everyone else already
+     * knows. Everyone else then adds a mask and proves they added a secret mask
+     * to the committed values. */
+    currentUserEncryptedTallies = tally_scores(currentTallyProofs, nextGenerator);
+    servers[0].import_updates(
+        pi,
+        previousVoteTally,
+        currentPseudonyms,
+        currentUserEncryptedTallies,
+        currentTallyProofs,
+        voteMatrix);
     
+    // go from A_0.5 to A_1
     for (size_t i = 0; i < servers.size(); i++)
     {
-        servers[i].epoch_part_two(pi, nextGenerator, encryptedTallies, encryptedTallyMasks);
-        servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+        servers[i].break_down_midway_pseudonyms(pi, nextGenerator);
+        servers[i].export_updates(
+            previousVoteTally,
+            currentPseudonyms,
+            currentUserEncryptedTallies,
+            currentTallyProofs,
+            voteMatrix);
         if (i < servers.size() - 1)
-            servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+        {
+            servers[i + 1].import_updates(
+                pi,
+                previousVoteTally,
+                currentPseudonyms,
+                currentUserEncryptedTallies,
+                currentTallyProofs,
+                voteMatrix);
+        }
     }
 
+    // At the end, make sure all servers have same information
     for (size_t i = 0; i < servers.size() - 1; i++)
-        servers[i].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
-
-    tallyProofs.clear();
-    for (size_t i = 0; i < encryptedTallies.size(); i++)
-        tallyProofs.push_back(generate_epoch_proof(pi, encryptedTallies[i]));
-}
-
-void PrsonaServerEntity::transmit_score(PrsonaClient& newUser) const
-{
-    Proof proofOfValidGenerator, proofOfValidSTPK, proofOfScore, proofOfCorrectVotes;
-    Curvepoint freshGenerator = get_fresh_generator(proofOfValidGenerator);
-
-    newUser.receive_fresh_generator(proofOfValidGenerator, freshGenerator);
-    Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(proofOfValidSTPK);
-
-    Scalar randomizationMask;
-    Proof proofOfOwner = newUser.generate_ownership_proof();
-    EGCiphertext score = get_current_tally(proofOfOwner, proofOfScore, shortTermPublicKey, true, randomizationMask);
-    newUser.receive_vote_tally(proofOfScore, score, false, randomizationMask);
-
-    std::vector<CurveBipoint> encryptedVotes = servers[0].get_current_votes_by(proofOfCorrectVotes, shortTermPublicKey);
-    newUser.receive_encrypted_votes(proofOfCorrectVotes, encryptedVotes, false);
-}
-
-EGCiphertext PrsonaServerEntity::get_default_tally(Proof& pi, const Curvepoint& shortTermPublicKey, Scalar& randomizationMask) const
-{
-    Proof unused;
-    EGCiphertext retval;
-
-    randomizationMask.set_random();
-
-    retval.mask = shortTermPublicKey * randomizationMask;
-    retval.encryptedMessage = get_fresh_generator(unused) * randomizationMask + get_blinding_generator() * PrsonaServer::defaultTally;
-
-    pi = generate_valid_default_tally_proof(retval, randomizationMask);
-
-    return retval;
-}
-
-Proof PrsonaServerEntity::generate_valid_default_tally_proof(const EGCiphertext& encryptedDefaultTally, const Scalar& lambda) const
-{
-    Proof retval;
-
-    if (!PrsonaServer::malicious_server)
     {
-        retval.basic = "PROOF";
-        return retval;
+        servers[i].import_updates(
+            pi,
+            previousVoteTally,
+            currentPseudonyms,
+            currentUserEncryptedTallies,
+            currentTallyProofs,
+            voteMatrix);
     }
-
-    retval.basic = "PROOF";
-    return retval;
 }
 
-Proof PrsonaServerEntity::generate_epoch_round_one_proof(const Proof& pi1, const Proof& pi2) const
+/*********************
+ * PRIVATE FUNCTIONS *
+ *********************/
+
+/*
+ * SCORE TALLYING
+ */
+
+/* Calculate scores, then scale the values appropriately,
+ * so they are in the correct range to be used as vote weights.
+ *
+ * We're treating it as if we are one server, so that server gets the updated
+ * weights to be sent to all other servers for the next epoch. */
+std::vector<EGCiphertext> PrsonaServerEntity::tally_scores(
+    std::vector<Proof>& tallyProofs, const Curvepoint& nextGenerator)
 {
-    Proof retval;
+    std::vector<EGCiphertext> retval;
+    Proof maxScoreProof;
+    std::vector<Scalar> decryptedTalliedScores = servers[0].tally_scores(
+                                                    tallyProofs);
+    mpz_class maxScorePossibleThisRound =
+        servers[0].get_max_possible_score(maxScoreProof).toInt() *
+        MAX_ALLOWED_VOTE;
+    mpz_class topOfScoreRange = retval.size() * MAX_ALLOWED_VOTE;
 
-    if (!PrsonaServer::malicious_server)
+    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
     {
-        retval.basic = "PROOF";
-        return retval;
-    }
-
-    retval.basic = "PROOF";
-    return retval;
-}
+        decryptedTalliedScores[i] =
+            Scalar(
+                (decryptedTalliedScores[i].toInt() * topOfScoreRange) /
+                maxScorePossibleThisRound
+            );
 
-Proof PrsonaServerEntity::generate_epoch_proof(const Proof& pi, const EGCiphertext& encryptedTally) const
-{
-    Proof retval;
-
-    if (!PrsonaServer::malicious_server)
-    {
-        retval.basic = "PROOF";
-        return retval;
+        EGCiphertext currCiphertext;
+        retval.push_back(currCiphertext);
+        Scalar currMask;
+        currMask.set_random();
+
+        // Give the server the new weights,
+        // to get passed around to the other servers
+        servers[0].bgn_system.encrypt(
+            servers[0].previousVoteTallies[i], decryptedTalliedScores[i]);
+        
+        retval[i].mask = servers[0].currentPseudonyms[i] * currMask;
+        retval[i].encryptedMessage =
+            (nextGenerator * currMask) +
+            (PrsonaServer::get_blinding_generator() * decryptedTalliedScores[i]);
     }
 
-    retval.basic = "PROOF";
     return retval;
 }
 
-bool PrsonaServerEntity::verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
-{
-    if (!PrsonaServer::malicious_client)
-        return pi.basic == "PROOF";
-
-    // Proof unused;
-    // Curvepoint g = get_fresh_generator(unused);
-    // Curvepoint u = pi.initParts[0];
-
-    // std::stringstream oracleInput;
-    // oracleInput << g << shortTermPublicKey << u;
-    // Scalar c = oracle(oracleInput.str());
-
-    // Scalar z = pi.responseParts[0];
-
-    // return (g * z) == (shortTermPublicKey * c + u);
-
-    return pi.basic == "PROOF";
-}
-
-EGCiphertext PrsonaServerEntity::get_current_tally(const Proof& ownerProof, Proof& serverProof, const Curvepoint& shortTermPublicKey, bool isOwner, Scalar& randomizationMask) const
-{
-    if (isOwner)
-    {
-        if (!verify_ownership_proof(ownerProof, shortTermPublicKey))
-            return EGCiphertext();
-    }
-
-    size_t requester = binary_search(shortTermPublicKey);
-
-    serverProof = tallyProofs[requester];
-
-    if (isOwner)
-        randomizationMask = encryptedTallyMasks[requester];
-
-    return encryptedTallies[requester];
-}
-
-std::vector<Scalar> PrsonaServerEntity::tally_scores(Proof& pi)
-{
-    std::vector<Scalar> retval = servers[0].tally_scores(pi);
-    mpz_class maxScorePossibleThisRound = servers[0].get_max_possible_score(pi).toInt() * maxAllowedVote;
-    mpz_class topOfScoreRange = retval.size() * maxAllowedVote;
-
-    for (size_t i = 0; i < retval.size(); i++)
-        retval[i] = Scalar((retval[i].toInt() * topOfScoreRange) / maxScorePossibleThisRound);
-
-    return retval;
-}
+/*
+ * BINARY SEARCH
+ */
 
-size_t PrsonaServerEntity::binary_search(const Curvepoint& shortTermPublicKey) const
+// Completely normal binary search
+size_t PrsonaServerEntity::binary_search(
+    const Curvepoint& shortTermPublicKey) const
 {
     return servers[0].binary_search(shortTermPublicKey);
 }