Procházet zdrojové kódy

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 před 3 roky
rodič
revize
6fedf2bb85

+ 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);
 }