Browse Source

there is now something that can actually be compiled; bugfixing remains to get it to run and be useful, though

tristangurtler 3 years ago
parent
commit
885c9e40cd

+ 92 - 0
prsona/Makefile

@@ -0,0 +1,92 @@
+INC_PATH = inc
+SRC_PATH = src
+OBJ_PATH = obj
+BIN_PATH = bin
+
+PRSONA_PATH = .
+PRSONA_INC_PATH = $(PRSONA_PATH)/$(INC_PATH)
+PRSONA_SRC_PATH = $(PRSONA_PATH)/$(SRC_PATH)
+PRSONA_OBJ_PATH = $(PRSONA_PATH)/$(OBJ_PATH)
+PRSONA_BIN_PATH = $(PRSONA_PATH)/$(BIN_PATH)
+
+BGN_PATH = ../BGN2/bgn2
+BGN_INC_PATH = $(BGN_PATH)/$(INC_PATH)
+BGN_SRC_PATH = $(BGN_PATH)/$(SRC_PATH)
+BGN_OBJ_PATH = $(BGN_PATH)/$(OBJ_PATH)
+BGN_BIN_PATH = $(BGN_PATH)/$(BIN_PATH)
+
+666_PATH = ../BGN2/dclxvi-20130329
+666_INC_PATH = $(666_PATH)/$(INC_PATH)
+666_SRC_PATH = $(666_PATH)/$(SRC_PATH)
+666_OBJ_PATH = $(666_PATH)/$(OBJ_PATH)
+666_BIN_PATH = $(666_PATH)/$(BIN_PATH)
+
+CPP = g++
+CPPFLAGS = -std=c++14 -Wall -I$(PRSONA_INC_PATH) -I$(BGN_INC_PATH) -I$(666_INC_PATH) -O2
+LDFLAGS = -lgmp -lgmpxx
+
+CC = gcc
+CFLAGS = -std=c99 -O3 -fomit-frame-pointer -I$(666_INC_PATH)
+C_LDFLAGS = -lm
+
+all: $(PRSONA_BIN_PATH) $(PRSONA_OBJ_PATH) $(BGN_OBJ_PATH) $(666_OBJ_PATH) $(PRSONA_BIN_PATH)/main
+
+$(PRSONA_BIN_PATH):
+	mkdir -p $@
+
+$(PRSONA_OBJ_PATH):
+	mkdir -p $@
+
+$(BGN_OBJ_PATH):
+	mkdir -p $@
+
+$(666_OBJ_PATH):
+	mkdir -p $@
+
+PRSONA_FULL_SRC = $(wildcard $(PRSONA_SRC_PATH)/*.cpp)
+PRSONA_SRC = $(filter-out $(PRSONA_SRC_PATH)/main.cpp, $(PRSONA_FULL_SRC)) 
+PRSONA_OBJ = $(patsubst $(PRSONA_SRC_PATH)/%.cpp, $(PRSONA_OBJ_PATH)/%.o, $(PRSONA_SRC))
+
+$(PRSONA_OBJ_PATH)/%.o: $(PRSONA_SRC_PATH)/%.cpp
+	$(CPP) $(CPPFLAGS) -DQHASM -c -o $@ $< 
+
+BGN_FULL_SRC = $(wildcard $(BGN_SRC_PATH)/*.cpp)
+BGN_SRC = $(filter-out $(BGN_SRC_PATH)/main.cpp, $(BGN_FULL_SRC)) 
+BGN_OBJ = $(patsubst $(BGN_SRC_PATH)/%.cpp, $(BGN_OBJ_PATH)/%.o, $(BGN_SRC))
+
+$(BGN_OBJ_PATH)/%.o: $(BGN_SRC_PATH)/%.cpp
+	$(CPP) $(CPPFLAGS) -DQHASM -c -o $@ $< 
+
+666_ALL_C_SRC = $(wildcard $(666_SRC_PATH)/*.c)
+666_C_SRC = $(filter-out $(666_SRC_PATH)/bilintest.c $(666_SRC_PATH)/speedtest.c $(666_SRC_PATH)/test_curvepoint_multiscalar.c $(666_SRC_PATH)/test_twistpoint_multiscalar.c $(666_SRC_PATH)/twistpoint_fp2_multiscalar.c $(666_SRC_PATH)/curvepoint_fp_multiscalar.c, $(666_ALL_C_SRC))
+666_C_OBJ = $(patsubst $(666_SRC_PATH)/%.c, $(666_OBJ_PATH)/%_c_with_as.o, $(666_C_SRC))
+
+$(666_OBJ_PATH)/%_c_with_as.o: $(666_SRC_PATH)/%.c $(666_INC_PATH)/%.h
+	$(CC) $(CFLAGS) -DQHASM -c -o $@ $<
+
+666_AS_SRC = $(wildcard $(666_SRC_PATH)/*.s)
+666_AS_OBJ = $(patsubst $(666_SRC_PATH)/%.s, $(666_OBJ_PATH)/%_as.o, $(666_AS_SRC))
+
+$(666_OBJ_PATH)/%_as.o: $(666_SRC_PATH)/%.s
+	$(CC) $(CFLAGS) -fPIC -c -o $@ $^
+
+$(BGN_OBJ_PATH)/bgn.a: $(BGN_OBJ) $(666_AS_OBJ) $(666_C_OBJ)
+	rm -f $@
+	ar cr $@ $^
+
+$(PRSONA_BIN_PATH)/main: $(PRSONA_OBJ_PATH)/main.o $(PRSONA_OBJ) $(BGN_OBJ_PATH)/bgn.a
+	$(CPP) $(CPPFLAGS) -no-pie -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean: prsona_clean bgn_clean 666_clean 
+
+prsona_clean: 
+	-rm $(PRSONA_BIN_PATH)/*
+	-rm $(PRSONA_OBJ_PATH)/*
+
+bgn_clean:
+	-rm $(BGN_OBJ_PATH)/*
+
+666_clean:
+	-rm $(666_OBJ_PATH)/*

BIN
prsona/bin/main


+ 1 - 1
prsona/inc/EGCiphertext.hpp

@@ -4,6 +4,6 @@
 struct EGCiphertext {    
     Curvepoint mask;
     Curvepoint encryptedMessage;
-}
+};
 
 #endif

+ 29 - 7
prsona/inc/client.hpp

@@ -2,28 +2,38 @@
 #define __PRSONA_CLIENT_HPP
 
 #include <unordered_map>
+#include <vector>
 
 #include "Curvepoint.hpp"
 #include "Scalar.hpp"
 #include "BGN.hpp"
+#include "EGCiphertext.hpp"
+#include "proof.hpp"
 
 class PrsonaClient {
     public:
         PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator);
 
-        Curvepoint get_long_term_public_key() const;
-        Curvepoint get_short_term_public_key() const;
+        static void set_malicious_server();
+        static void set_malicious_client();
 
-        void receive_score(const Proof& pi, const EGCiphertext& score, const Scalar& newSeed);
-        void make_votes(vector<CurveBipoint>& encryptedVotes, vector<Proof>& validVoteProofs, const vector<Scalar>& vote) const;
+        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);
+        void receive_encrypted_votes(const Proof& pi, const std::vector<CurveBipoint>& votes, bool isDefault);
         
         Proof generate_reputation_proof() const;
         bool verify_reputation_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
     private:
         static const Curvepoint elGamalGenerator;
-        const Curvepoint elGamalBlindGenerator;
+        static bool malicious_server;
+        static bool malicious_client;
         const BGNPublicKey serverPublicKey;
+        const Curvepoint elGamalBlindGenerator;
         
         Curvepoint currentFreshGenerator;
         EGCiphertext currentEncryptedScore;
@@ -31,11 +41,23 @@ class PrsonaClient {
         Scalar longTermPrivateKey;
         Scalar currentScore;
 
-        Proof generate_vote_proof(const Scalar& vote) const;
-        bool verify_score_proof(const Proof& pi) const;
+        std::vector<CurveBipoint> currEncryptedVotes;
 
         std::unordered_map<Curvepoint, Scalar, CurvepointHash> decryption_memoizer;
         Scalar max_checked;
+
+        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;
+
+        Proof generate_vote_proof(const std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote) const;
+        bool verify_score_proof(const Proof& pi) const;
 }; 
 
 #endif

+ 9 - 0
prsona/inc/proof.hpp

@@ -0,0 +1,9 @@
+#ifndef __PROOF_HPP
+#define __PROOF_HPP
+
+#include <string>
+
+typedef std::string Proof;
+
+#endif
+

+ 48 - 14
prsona/inc/server.hpp

@@ -1,41 +1,64 @@
 #ifndef __PRSONA_SERVER_HPP
 #define __PRSONA_SERVER_HPP
 
+#include <vector>
+
 #include "BGN.hpp"
 #include "Curvepoint.hpp"
 #include "Bipoint.hpp"
 #include "EGCiphertext.hpp"
+#include "proof.hpp"
 
-class PrsonaServer : public BGN {
+class PrsonaServer {
     public:
         PrsonaServer();
+        PrsonaServer(const BGN& other_bgn, const Curvepoint& other_blind_gen);
+
+        static void set_malicious_server();
+        static void set_malicious_client();
 
+        BGNPublicKey get_bgn_public_key() const;
         Curvepoint get_blinding_generator() const;
-        Curvepoint get_fresh_generator() const;
+        Curvepoint add_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const;
 
-        Curvepoint add_new_client(const Curvepoint& longTermPublicKey);
-        vector<EGCiphertext> epoch();
-        void receive_vote(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey);
+        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);
 
     private:
         static const Curvepoint elGamalGenerator;
-        
+        static const Scalar scalarN;
+        static const Scalar defaultTally;
+        static const Scalar defaultVote;
+        static bool malicious_server;
+        static bool malicious_client;
+        BGN bgn_system;
         Curvepoint elGamalBlindGenerator;
 
         Scalar currentSeed;
+        Scalar nextSeed;
 
-        vector<TwistBipoint> previousVoteTally;
-        vector<Curvepoint> currentPseudonyms;
+        std::vector<TwistBipoint> previousVoteTally;
+        std::vector<Curvepoint> currentPseudonyms;
         /* each element represents a vote by <rowID>
-         * applied to <colID> */
-        vector<vector<CurveBipoint>> voteMatrix;
+         * 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<std::vector<CurveBipoint>> voteMatrix;
 
-        template <typename T>
-        void shuffle_vote_matrix(vector<T>& otherVector);
+        friend class PrsonaServerEntity;
+        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 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);
+        void epoch_part_two(Proof& pi, std::vector<EGCiphertext>& encryptedTallies);
+
+        std::vector<size_t> order_data();
         void rerandomize_vote_matrix();
         
         size_t binary_search(const Curvepoint& index) const;
-        bool verify_vote_proof(CurveBipoint vote, Proof pi, PrsonaPublicKey shortTermPublicKey);
 
         struct SortingType {
             Curvepoint pseudonym;
@@ -43,7 +66,18 @@ class PrsonaServer : public BGN {
 
             bool operator<( const SortingType& rhs ) const
                 { return pseudonym < rhs.pseudonym; }
-        }
+        };
+
+        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_shuffle(const std::vector<size_t>& shuffle_order) const;
 }; 
 
 #endif

+ 40 - 0
prsona/inc/serverEntity.hpp

@@ -0,0 +1,40 @@
+#ifndef __PRSONA_SERVER_ENTITY_HPP
+#define __PRSONA_SERVER_ENTITY_HPP
+
+#include <vector>
+
+#include "client.hpp"
+#include "server.hpp"
+#include "proof.hpp"
+
+class PrsonaServerEntity {
+    public:
+        PrsonaServerEntity(size_t numServers);
+
+        BGNPublicKey get_bgn_public_key() const;
+        Curvepoint get_blinding_generator() const;
+        Curvepoint get_fresh_generator(Proof& pi) const;
+
+        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;
+
+    private:
+        std::vector<PrsonaServer> servers;
+        std::vector<EGCiphertext> encryptedTallies;
+        std::vector<Proof> tallyProofs;
+
+        EGCiphertext get_default_tally(Proof& pi, const Curvepoint& shortTermPublicKey) 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;
+
+        EGCiphertext get_current_tally(Proof& pi, const Curvepoint& shortTermPublicKey) const;
+
+        std::vector<Scalar> tally_scores(Proof& pi);
+        size_t binary_search(const Curvepoint& index) const;
+}; 
+
+#endif

BIN
prsona/obj/client.o


BIN
prsona/obj/main.o


BIN
prsona/obj/server.o


BIN
prsona/obj/serverEntity.o


+ 151 - 27
prsona/src/client.cpp

@@ -1,9 +1,11 @@
+#include <iostream>
+
 #include "client.hpp"
 
-extern const scalar_t bn_n;
-const Scalar PrsonaServer::scalarN(bn_n);
 extern const curvepoint_fp_t bn_curvegen;
 const Curvepoint PrsonaClient::elGamalGenerator(bn_curvegen);
+bool PrsonaClient::malicious_server = false;
+bool PrsonaClient::malicious_client = false;
 
 PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator)
 : serverPublicKey(serverPublicKey), elGamalBlindGenerator(elGamalBlindGenerator), max_checked(0)
@@ -12,28 +14,121 @@ PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint
     decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
 }
 
-Curvepoint PrsonaClient::get_long_term_public_key() const
+void PrsonaClient::set_malicious_server()
 {
-    return elGamalGenerator * longTermPrivateKey;
+    malicious_server = true;
 }
 
-Curvepoint PrsonaClient::get_short_term_public_key() const
+void PrsonaClient::set_malicious_client()
 {
+    malicious_client = true;
+}
+
+Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const
+{
+    pi = generate_stpk_proof();
+
     return currentFreshGenerator * longTermPrivateKey;
 }
 
-void PrsonaClient::receive_score(const Proof& pi, const EGCiphertext& score, const Curvepoint& newGenerator)
+void PrsonaClient::make_votes(Proof& pi, std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote, const std::vector<bool>& replace) const
+{
+    encryptedVotes.clear();
+
+    for (size_t i = 0; i < vote.size(); i++)
+    {
+        CurveBipoint currScore;
+        if (replace[i])
+            serverPublicKey.encrypt(currScore, vote[i]);
+        else
+            currScore = serverPublicKey.rerandomize(currEncryptedVotes[i]);
+
+        encryptedVotes.push_back(currScore);
+    }
+
+    pi = generate_vote_proof(encryptedVotes, vote);
+}
+
+void PrsonaClient::receive_fresh_generator(const Proof& pi, const Curvepoint& freshGenerator)
 {
-    if (!verify_score_proof(pi))
+    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)
+{
+    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))
+        {
+            std::cerr << "Could not verify proof of valid tally." << std::endl;
+            return;
+        }
+    }
 
     currentEncryptedScore = score;
-    currentFreshGenerator = newGenerator;
 
+    decrypt_score(score);
+}
+
+void PrsonaClient::receive_encrypted_votes(const Proof& pi, const std::vector<CurveBipoint>& votes, bool isDefault)
+{
+    if (isDefault)
+    {
+        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;
+        }
+    }
+
+    currEncryptedVotes = votes;
+}
+
+Proof PrsonaClient::generate_reputation_proof() const
+{
+    if (!malicious_client)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+bool PrsonaClient::verify_reputation_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
+{
+    if (!malicious_client)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
+}
+
+void PrsonaClient::decrypt_score(const EGCiphertext& score)
+{
+    //TOFIX
     Curvepoint s, hashedDecrypted;
-    Scalar decryptionKey = scalarN - longTermPrivateKey;
-    s = currentEncryptedScore.mask * decryptionKey;
-    hashedDecrypted = currentEncryptedScore.encryptedMessage + s;
+    Scalar decryptionKey = longTermPrivateKey;
+    s = score.mask * decryptionKey;
+    hashedDecrypted = score.encryptedMessage + s;
     
     auto lookup = decryption_memoizer.find(hashedDecrypted);
     if (lookup != decryption_memoizer.end())
@@ -53,41 +148,70 @@ void PrsonaClient::receive_score(const Proof& pi, const EGCiphertext& score, con
         max_checked++;
     }
 
-    curve_memoizer[decryptionCandidate] = max_checked;
+    decryption_memoizer[decryptionCandidate] = max_checked;
     currentScore = max_checked;
 }
 
-void PrsonaClient::make_votes(vector<CurveBipoint>& encryptedVotes, vector<Proof>& validVoteProofs, const vector<Scalar>& vote) const
+Proof PrsonaClient::generate_stpk_proof() const
 {
-    encryptedVotes.clear();
-    validVoteProofs.clear();
+    if (!malicious_client)
+        return "PROOF";
 
-    for (size_t i = 0; i < vote.size(); i++)
-    {
-        CurveBipoint currScore;
-        serverPublicKey.encrypt(currScore, vote[i]);
+    return "PROOF";
+}
 
-        encryptedVotes.push_back(currScore);
-        validVoteProofs.push_back(generate_vote_proof(vote[i], currScore));
-    }
+bool PrsonaClient::verify_generator_proof(const Proof& pi, const Curvepoint& generator) const
+{
+    if (!malicious_server)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
 }
 
-Proof PrsonaClient::generate_reputation_proof() const
+bool PrsonaClient::verify_default_tally_proof(const Proof& pi, const EGCiphertext& score) const
 {
-    
+    if (!malicious_server)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
+}
+
+bool PrsonaClient::verify_valid_tally_proof(const Proof& pi, const EGCiphertext& score) const
+{
+    if (!malicious_server)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
+}
+
+bool PrsonaClient::verify_default_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
+{
+    if (!malicious_server)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
 }
 
-bool PrsonaClient::verify_reputation_proof(const Proof& pi, const PrsonaPublicKey& shortTermPublicKey) const
+bool PrsonaClient::verify_valid_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
 {
+    if (!malicious_server)
+        return pi == "PROOF";
 
+    return pi == "PROOF";
 }
 
-Proof PrsonaClient::generate_vote_proof(const Scalar& vote, const CurveBipoint& encryptedVote) const
+Proof PrsonaClient::generate_vote_proof(const std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote) const
 {
+    if (!malicious_client)
+        return "PROOF";
 
+    return "PROOF";
 }
 
-bool verify_score_proof(const Proof& pi) const
+bool PrsonaClient::verify_score_proof(const Proof& pi) const
 {
+    if (!malicious_server)
+        return pi == "PROOF";
 
+    return pi == "PROOF";
 }

+ 185 - 0
prsona/src/main.cpp

@@ -0,0 +1,185 @@
+// #include <boost/program_options.hpp>
+// namespace po = boost::program_options;
+
+#include <iostream>
+#include <algorithm>
+#include <random>
+#include <chrono>
+
+#include "BGN.hpp"
+#include "client.hpp"
+#include "server.hpp"
+#include "serverEntity.hpp"
+
+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) 
+// {
+//     string config_file;
+
+//     // Declare a group of options that will be 
+//     // allowed only on command line
+//     po::options_description generic("General options");
+//     generic.add_options()
+//         ("help", "produce this help message")
+//         ("config,c", po::value<string>(&config_file)->default_value(""),
+//               "name of a configuration file")
+//         ;
+
+//     // Declare a group of options that will be 
+//     // allowed both on command line and in
+//     // 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")
+//         ("seed", po::value<string>(&seedStr)->default_value("default"),
+//             "the random seed to use for this test")
+//         ;
+
+//     // Hidden options, will be allowed both on command line and
+//     // in config file, but will not be shown to the user.
+//     po::options_description hidden("Hidden options");
+//     hidden.add_options()
+//         ("number-servers,S", po::value<size_t>(&numServers)->default_value(2), 
+//               "number of servers in test")
+//         ("number-users,N", po::value<size_t>(&numClients)->default_value(5), 
+//               "number of users in test")
+//         ("number-rounds,R", po::value<size_t>(&numRounds)->default_value(3), 
+//               "number of rounds to perform in test")
+//         ("number-votes,V", po::value<size_t>(&numVotes)->default_value(3), 
+//               "number of votes each user makes per round during test")
+//         ;
+    
+//     po::options_description cmdline_options;
+//     cmdline_options.add(generic).add(config).add(hidden);
+
+//     po::options_description config_file_options;
+//     config_file_options.add(config).add(hidden);
+
+//     po::options_description visible("Allowed options");
+//     visible.add(generic).add(config);
+    
+//     po::positional_options_description p;
+//     p.add("number-servers", 1);
+//     p.add("number-users", 1);
+//     p.add("number-rounds", 1);
+//     p.add("number-votes", 1);
+    
+//     po::variables_map vm;
+//     store(po::command_line_parser(argc, argv).
+//           options(cmdline_options).positional(p).run(), vm);
+//     notify(vm);
+
+//     if (!config_file.empty())
+//     {
+//         ifstream config(config_file.c_str());
+//         if (!config)
+//         {
+//             cerr << "Cannot open config file: " << config_file << "\n";
+//             return 2;
+//         }
+//         else
+//         {
+//             store(parse_config_file(config, config_file_options), vm);
+//             notify(vm);
+//         }
+//     }
+
+//     if (vm.count("help"))
+//     {
+//         cout << visible << endl;
+//         return 1;
+//     }
+
+//     maliciousServers = vm.count("malicious-servers");
+//     maliciousUsers = vm.count("malicious-users");
+
+//     return 0;
+// }
+
+void epoch(default_random_engine& generator, PrsonaServerEntity& servers, vector<PrsonaClient>& users, size_t numVotes)
+{
+    Proof unused;
+    uniform_int_distribution<int> voteDistribution(0, 3);
+    size_t numUsers = users.size();
+
+    for (size_t i = 0; i < numUsers; i++)
+    {
+        vector<Scalar> votes;
+        vector<bool> replace;
+        for (size_t j = 0; j < numUsers; j++)
+        {
+            votes.push_back(Scalar(voteDistribution(generator)));
+            replace.push_back(j < numVotes);
+        }
+
+        shuffle(replace.begin(), replace.end(), generator);
+
+        vector<CurveBipoint> encryptedVotes;
+        Proof pi;
+        users[i].make_votes(pi, encryptedVotes, votes, replace);
+
+        servers.receive_vote(pi, encryptedVotes, users[i].get_short_term_public_key(unused));
+    }
+
+    servers.epoch();
+
+    for (size_t i = 0; i < numUsers; i++)
+        servers.transmit_score(users[i]);
+}
+
+int main(int argc, char *argv[])
+{
+    size_t numServers, numUsers, numRounds, numVotesPerRound;
+    bool maliciousServers, maliciousUsers;
+    string seedStr;
+
+    // err - 1 because the help text returns 1 (and shouldn't flag as an error occurring)
+    // int err;
+    // if ((err = argparse(argc, argv, numServers, numUsers, numRounds, numVotesPerRound, maliciousServers, maliciousUsers, seedStr)))
+    //     return (err - 1);
+
+    numServers = 2;
+    numUsers = 5;
+    numRounds = 3;
+    numVotesPerRound = 3;
+    maliciousServers = false;
+    maliciousUsers = false;
+
+    if (maliciousServers)
+    {
+        PrsonaServer::set_malicious_server();
+        PrsonaClient::set_malicious_server();
+    }
+
+    if (maliciousUsers)
+    {
+        PrsonaServer::set_malicious_client();
+        PrsonaClient::set_malicious_client();
+    }
+
+    PrsonaServerEntity servers(numServers);
+    BGNPublicKey bgnPublicKey = servers.get_bgn_public_key();
+    Curvepoint EGBlindGenerator = servers.get_blinding_generator();
+
+    vector<PrsonaClient> users;
+    for (size_t i = 0; i < numUsers; i++)
+    {
+        PrsonaClient currUser(bgnPublicKey, EGBlindGenerator);
+        servers.add_new_client(currUser);
+
+        users.push_back(currUser);
+    }
+
+    seed_seq seed(seedStr.begin(), seedStr.end());
+    default_random_engine generator(seed);
+
+    for (size_t i = 0; i < numRounds; i++)
+    {
+        cout << "Round " << i << " commencing." << endl;
+        epoch(generator, servers, users, numVotesPerRound);
+    }
+
+    return 0;
+}

+ 235 - 73
prsona/src/server.cpp

@@ -1,9 +1,16 @@
+#include <iostream>
+
 #include "server.hpp"
 
-extern const scalar_t bn_n;
-const Scalar PrsonaServer::scalarN(bn_n);
 extern const curvepoint_fp_t bn_curvegen;
 const Curvepoint PrsonaServer::elGamalGenerator(bn_curvegen);
+extern const scalar_t bn_n;
+const Scalar PrsonaServer::scalarN(bn_n);
+const Scalar PrsonaServer::defaultTally(0);
+const Scalar PrsonaServer::defaultVote(0);
+
+bool PrsonaServer::malicious_server = false;
+bool PrsonaServer::malicious_client = false;
 
 PrsonaServer::PrsonaServer()
 {
@@ -15,102 +22,201 @@ PrsonaServer::PrsonaServer()
     currentSeed.set_random();
 }
 
+PrsonaServer::PrsonaServer(const BGN& other_bgn, const Curvepoint& other_blind_gen)
+: bgn_system(other_bgn), elGamalBlindGenerator(other_blind_gen)
+{
+    currentSeed.set_random();
+}
+
+void PrsonaServer::set_malicious_server()
+{
+    malicious_server = true;
+}
+
+void PrsonaServer::set_malicious_client()
+{
+    malicious_client = true;
+}
+
+BGNPublicKey PrsonaServer::get_bgn_public_key() const
+{
+    return bgn_system.get_public_key();
+}
+
 Curvepoint PrsonaServer::get_blinding_generator() const
 {
     return elGamalBlindGenerator;
 }
 
-Curvepoint PrsonaServer::get_fresh_generator() const
+Curvepoint PrsonaServer::add_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const
+{
+    pi = generate_valid_fresh_generator_proof(pi);
+
+    return currGenerator * currentSeed;
+}
+
+std::vector<CurveBipoint> PrsonaServer::get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
-    return elGamalGenerator * currentSeed;
+    std::vector<CurveBipoint> retval;
+    size_t voteSubmitter = binary_search(shortTermPublicKey);
+    retval = voteMatrix[voteSubmitter];
+
+    pi = generate_votes_valid_proof(retval, shortTermPublicKey);
+    
+    return retval;
 }
 
-Curvepoint PrsonaServer::add_new_client(const Curvepoint& longTermPublicKey)
+void PrsonaServer::add_new_client(const Proof& proofOfValidKey, Proof& proofOfValidAddition, const Curvepoint& shortTermPublicKey)
 {
-    Curvepoint newPseudonym = longTermPublicKey * currentSeed;
-    currentPseudonyms.push_back(newPseudonym);
+    if (!verify_valid_key_proof(proofOfValidKey, shortTermPublicKey))
+    {
+        std::cerr << "Could not verify proof of valid key." << std::endl;
+        return;
+    }
+
+    currentPseudonyms.push_back(shortTermPublicKey);
 
     TwistBipoint newTalliedVote;
-    encrypt(newTalliedVote, Scalar(0));
+    bgn_system.encrypt(newTalliedVote, Scalar(defaultTally));
     previousVoteTally.push_back(newTalliedVote);
 
-    CurveBipoint defaultVote;
-    encrypt(defaultVote, Scalar(0));
-    vector<CurveBipoint> newRow;
+    CurveBipoint encryptedDefaultVote;
+    bgn_system.encrypt(encryptedDefaultVote, Scalar(defaultVote));
+    std::vector<CurveBipoint> newRow;
     for (size_t i = 0; i < voteMatrix.size(); i++)
     {
-        rerandomize(defaultVote);
-        voteMatrix[i].push_back(defaultVote);
-        rerandomize(defaultVote);
-        newRow.push_back(defaultVote);
+        encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
+        voteMatrix[i].push_back(encryptedDefaultVote);
+
+        encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
+        newRow.push_back(encryptedDefaultVote);
     }
 
-    rerandomize(defaultVote);
-    newRow.push_back(defaultVote);
+    encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
+    newRow.push_back(encryptedDefaultVote);
     voteMatrix.push_back(newRow);
 
-    return newPseudonym;
+    order_data();
+
+    proofOfValidAddition = generate_proof_of_added_user(shortTermPublicKey);
 }
 
-vector<EGCiphertext> PrsonaServer::epoch()
+void PrsonaServer::receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
 {
-    Scalar inverseSeed = scalarN - currentSeed;
-    Scalar nextSeed;
-    nextSeed.set_random();
+    if (!verify_vote_proof(pi, votes, shortTermPublicKey))
+    {
+        std::cerr << "Could not verify votes." << std::endl;
+        return;
+    }
+
+    size_t voteSubmitter = binary_search(shortTermPublicKey);
+    voteMatrix[voteSubmitter] = votes;
+}
+
+const BGN& PrsonaServer::get_bgn_details() const
+{
+    return bgn_system;
+}
 
-    vector<Quadripoint> BGNEncryptedTallies;
-    vector<Scalar> decryptedTallies;
-    vector<EGCiphertext> EGEncryptedTallies(currentPseudonyms.size());
+std::vector<Scalar> PrsonaServer::tally_scores(Proof& pi)
+{
+    std::vector<Quadripoint> BGNEncryptedTallies;
+    std::vector<Scalar> decryptedTallies;
     for (size_t i = 0; i < voteMatrix.size(); i++)
     {
-        vector<Quadripoint> currTally;
+        std::vector<Quadripoint> weightedVotes;
 
         for (size_t j = 0; j < previousVoteTally.size(); j++)
         {
-            Quadripoint curr;
-            homomorphic_multiplication(curr, voteMatrix[j][i], previousVoteTally[j]);
-            currTally.push_back(curr);
+            Quadripoint curr = bgn_system.homomorphic_multiplication(voteMatrix[j][i], previousVoteTally[j]);
+            weightedVotes.push_back(curr);
         }
 
-        BGNEncryptedTallies.push_back(std::accumulate(currTally.begin(), currTally.end(), Quadripoint()));
+        Quadripoint currEncryptedTally = weightedVotes[0];
+        for (size_t j = 1; j < weightedVotes.size(); j++)
+            currEncryptedTally = bgn_system.homomorphic_addition(currEncryptedTally, weightedVotes[j]);
+
+        currEncryptedTally = bgn_system.rerandomize(currEncryptedTally);
+        decryptedTallies.push_back(bgn_system.decrypt(currEncryptedTally));
     }
-    
-    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+
+    pi = generate_proof_of_correct_tally(BGNEncryptedTallies, decryptedTallies);
+
+    return decryptedTallies;
+}
+
+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;
+}
+
+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))
     {
-        currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
-        decryptedTallies.push_back(decrypt(BGNEncryptedTallies[i]));
+        std::cerr << "Could not verify valid update." << std::endl;
+        return;
     }
-    shuffle_vote_matrix(decryptedTallies);
-    
-    Curvepoint nextGenerator = elGamalGenerator * nextSeed;
-    for (size_t i = 0; i < currentPseudonyms.size(); i++)
-    {
-        Scalar currMask;
-        currMask.set_random();
 
-        previousVoteTally[i] = encrypt(decryptedTallies[i]);
+    previousVoteTally = otherPreviousVoteTally;
+    currentPseudonyms = otherCurrentPseudonyms;
+    voteMatrix = otherVoteMatrix;
+}
+
+void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies)
+{
+    nextSeed.set_random();
+    nextGenerator = nextGenerator * nextSeed;
+
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+        currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
         
-        EGEncryptedTallies[i].mask = currentPseudonyms[i] * currMask;
-        EGEncryptedTallies[i].encryptedMessage = (nextGenerator * currMask) + (elGamalBlindGenerator * decryptedTallies[i]);
-    }
+    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);
+}
+
+void PrsonaServer::epoch_part_two(Proof& pi, std::vector<EGCiphertext>& encryptedTallies)
+{
+    // TOFIX
+    Scalar inverseSeed = scalarN - currentSeed;
 
     for (size_t i = 0; i < currentPseudonyms.size(); i++)
     {
         currentPseudonyms[i] = currentPseudonyms[i] * inverseSeed;
-        EGEncryptedTallies[i].mask = EGEncryptedTallies[i].mask * inverseSeed;
+        encryptedTallies[i].mask = encryptedTallies[i].mask * inverseSeed;
     }
-    shuffle_vote_matrix(EGEncryptedTallies);
 
-    return EGEncryptedTallies;
+    std::vector<size_t> shuffleOrder = order_data();
+    rerandomize_vote_matrix();
+
+    std::vector<EGCiphertext> reorderedTallies;
+    for (size_t i = 0; i < shuffleOrder.size(); i++)
+        reorderedTallies.push_back(encryptedTallies[shuffleOrder[i]]);
+    encryptedTallies = reorderedTallies;
+
+    pi = generate_proof_of_shuffle(shuffleOrder);
+
+    currentSeed = nextSeed;
 }
 
-template <typename T>
-void PrsonaServer::shuffle_vote_matrix(vector<T>& otherVector)
+std::vector<size_t> PrsonaServer::order_data()
 {
-    vector<sorting_t> sortTracker;
+    std::vector<size_t> retval;
+    std::vector<SortingType> sortTracker;
     for (size_t i = 0; i < currentPseudonyms.size(); i++)
     {
-        sorting_t curr;
+        SortingType curr;
         
         curr.pseudonym = currentPseudonyms[i];
         curr.index = i;
@@ -120,31 +226,30 @@ void PrsonaServer::shuffle_vote_matrix(vector<T>& otherVector)
 
     std::sort(sortTracker.begin(), sortTracker.end());
 
-    vector<Curvepoint> newPseudonyms;
-    vector<TwistBipoint> newVoteTallies;
-    vector<vector<CurveBipoint>> newVoteMatrix;
-    vector<T> newOtherVector;
+    std::vector<Curvepoint> newPseudonyms;
+    std::vector<TwistBipoint> newVoteTallies;
+    std::vector<std::vector<CurveBipoint>> newVoteMatrix;
 
-    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+    for (size_t i = 0; i < sortTracker.size(); i++)
     {
         newPseudonyms.push_back(sortTracker[i].pseudonym);
         newVoteTallies.push_back(previousVoteTally[sortTracker[i].index]);
-        newOtherVector.push_back(otherVector[sortTracker[i].index]);
 
-        vector<CurveBipoint> currNewRow;
+        std::vector<CurveBipoint> currNewRow;
         for (size_t j = 0; j < currentPseudonyms.size(); j++)
         {
             currNewRow.push_back(voteMatrix[sortTracker[i].index][sortTracker[j].index]);
         }
         newVoteMatrix.push_back(currNewRow);
+
+        retval.push_back(sortTracker[i].index);
     }
 
     currentPseudonyms = newPseudonyms;
     previousVoteTally = newVoteTallies;
     voteMatrix = newVoteMatrix;
-    otherVector = newOtherVector;
 
-    rerandomize_vote_matrix();
+    return retval;
 }
 
 void PrsonaServer::rerandomize_vote_matrix()
@@ -153,21 +258,11 @@ void PrsonaServer::rerandomize_vote_matrix()
     {
         for (size_t j = 0; j < voteMatrix[0].size(); j++)
         {
-            voteMatrix[i][j] = rerandomize(voteMatrix[i][j]);
+            voteMatrix[i][j] = bgn_system.rerandomize(voteMatrix[i][j]);
         }
     }
 }
 
-void PrsonaServer::receive_vote(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
-{
-    if (!verify_vote_proof(pi, votes, shortTermPublicKey))
-        return;
-
-    size_t voteSubmitter = binary_search(shortTermPublicKey);
-    voteMatrix[voteSubmitter] = votes;
-    rerandomize_vote_matrix();
-}
-
 size_t PrsonaServer::binary_search(const Curvepoint& index) const
 {
     size_t lo, hi;
@@ -187,7 +282,74 @@ size_t PrsonaServer::binary_search(const Curvepoint& index) const
     return lo;
 }
 
-bool PrsonaServer::verify_vote_proof(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
+bool PrsonaServer::verify_valid_key_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
+{
+    if (!malicious_client)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
+}
+
+bool PrsonaServer::verify_vote_proof(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
+{
+    if (!malicious_client)
+        return pi == "PROOF";
+
+    return pi == "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
+{
+    if (!malicious_server)
+        return pi == "PROOF";
+
+    return pi == "PROOF";
+}
+
+Proof PrsonaServer::generate_valid_fresh_generator_proof(const Proof& oldProof) const
+{
+    if (!malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServer::generate_votes_valid_proof(const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
+{
+    if (!malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServer::generate_proof_of_added_user(const Curvepoint& shortTermPublicKey) const
+{
+    if (!malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
+{
+    if (!malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServer::generate_proof_of_correct_tally(const std::vector<Quadripoint>& BGNEncryptedTallies, const std::vector<Scalar>& decryptedTallies) const
+{
+    if (!malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServer::generate_proof_of_shuffle(const std::vector<size_t>& shuffle_order) const
 {
+    if (!malicious_server)
+        return "PROOF";
 
+    return "PROOF";
 }

+ 202 - 0
prsona/src/serverEntity.cpp

@@ -0,0 +1,202 @@
+#include <iostream>
+
+#include "serverEntity.hpp"
+
+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;
+
+    PrsonaServer firstServer;
+    servers.push_back(firstServer);
+
+    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);
+    }
+}
+
+BGNPublicKey PrsonaServerEntity::get_bgn_public_key() const
+{
+    return servers[0].get_bgn_public_key();
+}
+
+Curvepoint PrsonaServerEntity::get_blinding_generator() const
+{
+    return servers[0].get_blinding_generator();
+}
+
+Curvepoint PrsonaServerEntity::get_fresh_generator(Proof& pi) const
+{
+    Curvepoint retval = PrsonaServer::elGamalGenerator;
+    for (size_t j = 0; j < servers.size(); j++)
+        servers[j].add_seed_to_generator(pi, retval);
+
+    return retval;
+}
+
+void PrsonaServerEntity::add_new_client(PrsonaClient& newUser)
+{
+    Proof proofOfValidGenerator, proofOfValidSTPK, proofOfCorrectAddition, proofOfDefaultTally, proofOfValidVotes;
+    Curvepoint freshGenerator = get_fresh_generator(proofOfValidGenerator);
+
+    newUser.receive_fresh_generator(proofOfValidGenerator, freshGenerator);
+    Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(proofOfValidSTPK);
+
+    servers[0].add_new_client(proofOfValidSTPK, proofOfCorrectAddition, shortTermPublicKey);
+
+    std::vector<TwistBipoint> previousVoteTally;
+    std::vector<Curvepoint> currentPseudonyms;
+    std::vector<std::vector<CurveBipoint>> voteMatrix;
+    servers[0].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+
+    for (size_t j = 1; j < servers.size(); j++)
+        servers[j].import_updates(proofOfCorrectAddition, previousVoteTally, currentPseudonyms, voteMatrix);
+
+    EGCiphertext defaultTally = get_default_tally(proofOfDefaultTally, shortTermPublicKey);
+    newUser.receive_vote_tally(proofOfDefaultTally, defaultTally, true);
+
+    std::vector<CurveBipoint> encryptedDefaults = servers[0].get_current_votes_by(proofOfValidVotes, shortTermPublicKey);
+    newUser.receive_encrypted_votes(proofOfValidVotes, encryptedDefaults, true);
+}
+
+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()
+{
+    Proof pi, proofOfCorrectTally;
+    Curvepoint nextGenerator = PrsonaServer::elGamalGenerator;
+    std::vector<Scalar> decryptedTalliedScores = tally_scores(proofOfCorrectTally);
+    std::vector<TwistBipoint> previousVoteTally;
+    std::vector<Curvepoint> currentPseudonyms;
+    std::vector<std::vector<CurveBipoint>> voteMatrix;
+
+    for (size_t i = 0; i < servers.size() - 1; i++)
+    {
+        servers[i].epoch_part_one(pi, nextGenerator, decryptedTalliedScores);
+
+        servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+        servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+    }
+
+    servers[servers.size() - 1].epoch_part_one(pi, nextGenerator, decryptedTalliedScores);
+
+    servers[servers.size() - 1].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+
+    encryptedTallies.clear();
+    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
+    {
+        EGCiphertext currCiphertext;
+        encryptedTallies.push_back(currCiphertext);
+
+        Scalar currMask;
+        currMask.set_random();
+
+        servers[0].bgn_system.encrypt(previousVoteTally[i], decryptedTalliedScores[i]);
+        
+        encryptedTallies[i].mask = currentPseudonyms[i] * currMask;
+        encryptedTallies[i].encryptedMessage = (nextGenerator * currMask) + (get_blinding_generator() * decryptedTalliedScores[i]);
+    }
+
+    pi = generate_epoch_round_one_proof(pi, proofOfCorrectTally);
+    servers[0].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+    
+    for (size_t i = 0; i < servers.size() - 1; i++)
+    {
+        servers[i].epoch_part_two(pi, encryptedTallies);
+
+        servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+        servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+    }
+
+    servers[servers.size() - 1].epoch_part_two(pi, encryptedTallies);
+
+    servers[servers.size() - 1].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
+    for (size_t i = 0; i < servers.size() - 1; i++)
+        servers[i].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
+
+    for (size_t i = 0; i < encryptedTallies.size(); i++)
+        tallyProofs[i] = 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);
+
+    EGCiphertext score = get_current_tally(proofOfScore, shortTermPublicKey);
+    newUser.receive_vote_tally(proofOfScore, score, false);
+
+    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) const
+{
+    Proof unused;
+    EGCiphertext retval;
+
+    Scalar lambda;
+    lambda.set_random();
+
+    retval.mask = shortTermPublicKey * lambda;
+    retval.encryptedMessage = get_fresh_generator(unused) * lambda + get_blinding_generator() * PrsonaServer::defaultTally;
+
+    pi = generate_valid_default_tally_proof(retval, lambda);
+
+    return retval;
+}
+
+Proof PrsonaServerEntity::generate_valid_default_tally_proof(const EGCiphertext& encryptedDefaultTally, const Scalar& lambda) const
+{
+    if (!PrsonaServer::malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServerEntity::generate_epoch_round_one_proof(const Proof& pi1, const Proof& pi2) const
+{
+    if (!PrsonaServer::malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+Proof PrsonaServerEntity::generate_epoch_proof(const Proof& pi, const EGCiphertext& encryptedTally) const
+{
+    if (!PrsonaServer::malicious_server)
+        return "PROOF";
+
+    return "PROOF";
+}
+
+EGCiphertext PrsonaServerEntity::get_current_tally(Proof& pi, const Curvepoint& shortTermPublicKey) const
+{
+    size_t requester = binary_search(shortTermPublicKey);
+
+    pi = tallyProofs[requester];
+
+    return encryptedTallies[requester];
+}
+
+std::vector<Scalar> PrsonaServerEntity::tally_scores(Proof& pi)
+{
+    return servers[0].tally_scores(pi);
+}
+
+size_t PrsonaServerEntity::binary_search(const Curvepoint& shortTermPublicKey) const
+{
+    return servers[0].binary_search(shortTermPublicKey);
+}