Browse Source

fix for scaling issue applied; code changed to enable the actual structure proofs will take in the future; code added to enable reputation proofs (although this code is currently commented out, as the oracle function is not yet implemented, so attempting compilation with it in will cause a linker error

tristangurtler 3 years ago
parent
commit
667cf20ce1

+ 7 - 3
prsona/inc/client.hpp

@@ -22,11 +22,14 @@ class PrsonaClient {
         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_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);
         
-        Proof generate_reputation_proof() const;
-        bool verify_reputation_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
+        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;
 
     private:
         static Curvepoint elGamalGenerator;
@@ -37,6 +40,7 @@ class PrsonaClient {
         
         Curvepoint currentFreshGenerator;
         EGCiphertext currentEncryptedScore;
+        Scalar currentRandomizationMask;
 
         Scalar longTermPrivateKey;
         Scalar inversePrivateKey;

+ 16 - 1
prsona/inc/proof.hpp

@@ -2,8 +2,23 @@
 #define __PROOF_HPP
 
 #include <string>
+#include <vector>
+#include <sstream>
 
-typedef std::string Proof;
+#include "Scalar.hpp"
+#include "Curvepoint.hpp"
+
+// typedef std::string Proof;
+
+struct Proof {    
+    std::string basic;
+    std::vector<Curvepoint> partialUniversals;
+    std::vector<Curvepoint> initParts;
+    std::vector<Scalar> challengeParts;
+    std::vector<Scalar> responseParts;
+};
+
+Scalar oracle(std::string input);
 
 #endif
 

+ 4 - 2
prsona/inc/server.hpp

@@ -50,10 +50,11 @@ class PrsonaServer {
         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);
+        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);
-        void epoch_part_two(Proof& pi, std::vector<EGCiphertext>& encryptedTallies);
+        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();
@@ -77,6 +78,7 @@ class PrsonaServer {
         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;
 }; 
 

+ 4 - 2
prsona/inc/serverEntity.hpp

@@ -17,6 +17,7 @@ class PrsonaServerEntity {
         Scalar decrypt(const CurveBipoint& input);
 
         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;
 
         void add_new_client(PrsonaClient& newUser);
         void receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey);
@@ -26,15 +27,16 @@ class PrsonaServerEntity {
     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) const;
+        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;
 
-        EGCiphertext get_current_tally(Proof& pi, const Curvepoint& shortTermPublicKey) const;
+        bool verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
         std::vector<Scalar> tally_scores(Proof& pi);
         size_t binary_search(const Curvepoint& index) const;

+ 232 - 23
prsona/src/client.cpp

@@ -9,6 +9,18 @@ Curvepoint PrsonaClient::elGamalGenerator = Curvepoint();
 bool PrsonaClient::malicious_server = false;
 bool PrsonaClient::malicious_client = false;
 
+mpz_class log2(mpz_class x)
+{
+    mpz_class retval = 0;
+    while (x > 0)
+    {
+        retval++;
+        x = x >> 1;
+    }
+
+    return retval;
+}
+
 PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator)
 : serverPublicKey(serverPublicKey), elGamalBlindGenerator(elGamalBlindGenerator), max_checked(0)
 {
@@ -66,7 +78,7 @@ void PrsonaClient::receive_fresh_generator(const Proof& pi, const Curvepoint& fr
     currentFreshGenerator = freshGenerator;
 }
 
-void PrsonaClient::receive_vote_tally(const Proof& pi, const EGCiphertext& score, bool isDefault)
+void PrsonaClient::receive_vote_tally(const Proof& pi, const EGCiphertext& score, bool isDefault, const Scalar& randomizationMask)
 {
     if (isDefault)
     {
@@ -86,6 +98,7 @@ void PrsonaClient::receive_vote_tally(const Proof& pi, const EGCiphertext& score
     }
 
     currentEncryptedScore = score;
+    currentRandomizationMask = randomizationMask;
     decrypt_score(score);
 }
 
@@ -111,20 +124,202 @@ void PrsonaClient::receive_encrypted_votes(const Proof& pi, const std::vector<Cu
     currEncryptedVotes = votes;
 }
 
-Proof PrsonaClient::generate_reputation_proof() const
+std::vector<Proof> PrsonaClient::generate_reputation_proof(const Scalar& threshold) const
+{
+    std::vector<Proof> retval;
+
+    if (threshold > currentScore)
+        return retval;
+
+    if (!malicious_client)
+    {
+        Proof currProof;
+        currProof.basic = "PROOF";
+
+        retval.push_back(currProof);
+        return retval;
+    }
+
+    // retval.push_back(generate_ownership_proof());
+
+    // mpz_class proofVal = currentScore.curveSub(threshold).toInt();
+    // mpz_class proofBits = log2(currEncryptedVotes.size() * 3 - threshold.toInt());
+
+    // std::vector<Scalar> masksPerBit;
+    // masksPerBit.push_back(currentRandomizationMask);
+    // 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)));
+    // }
+
+    // for (size_t i = 0; i < proofBits; i++)
+    // {
+    //     Proof currProof;
+    //     std::stringstream oracleInput;
+    //     oracleInput << currentFreshGenerator << elGamalBlindGenerator;
+    
+    //     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);
+    return retval;
+}
+
+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)
+        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;
+    // }
+
+    // Proof unused, serverProof;
+    // Scalar alsoUnused;
+    // EGCiphertext encryptedScore = servers.get_current_tally(unused, serverProof, shortTermPublicKey, false, alsoUnused);
+
+    // Scalar negThreshold;
+    // negThreshold = Scalar(0).curveSub(threshold);
+
+    // Curvepoint scoreCommitment = encryptedScore.encryptedMessage + elGamalBlindGenerator * negThreshold;
+    // if (X != scoreCommitment)
+    //     return false;
+
+    // return true;
+
+    return pi[0].basic == "PROOF";
+}
+
+Proof PrsonaClient::generate_ownership_proof() const
 {
+    Proof retval;
     if (!malicious_client)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
+
+    // std::stringstream oracleInput;
+    
+    // Scalar r;
+    // r.set_random();
 
-    return "PROOF";
+    // 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;
+
+    retval.basic = "PROOF";
+    return retval;
 }
 
-bool PrsonaClient::verify_reputation_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
+bool PrsonaClient::verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
     if (!malicious_client)
-        return pi == "PROOF";
+        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 pi == "PROOF";
+    // return (currentFreshGenerator * z) == (shortTermPublicKey * c + u);
+
+    return pi.basic == "PROOF";
 }
 
 void PrsonaClient::decrypt_score(const EGCiphertext& score)
@@ -137,6 +332,7 @@ void PrsonaClient::decrypt_score(const EGCiphertext& score)
     if (lookup != decryption_memoizer.end())
     {
         currentScore = lookup->second;
+        // std::cout << "Decrypted score: " << currentScore << std::endl;
         return;
     }
 
@@ -153,68 +349,81 @@ void PrsonaClient::decrypt_score(const EGCiphertext& score)
 
     decryption_memoizer[decryptionCandidate] = max_checked;
     currentScore = max_checked;
+    // std::cout << "Decrypted score: " << currentScore << std::endl;
 }
 
 Proof PrsonaClient::generate_stpk_proof() const
 {
+    Proof retval;
+
     if (!malicious_client)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 bool PrsonaClient::verify_generator_proof(const Proof& pi, const Curvepoint& generator) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 bool PrsonaClient::verify_default_tally_proof(const Proof& pi, const EGCiphertext& score) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 bool PrsonaClient::verify_valid_tally_proof(const Proof& pi, const EGCiphertext& score) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 bool PrsonaClient::verify_default_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 bool PrsonaClient::verify_valid_votes_proof(const Proof& pi, const std::vector<CurveBipoint>& votes) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 Proof PrsonaClient::generate_vote_proof(const std::vector<CurveBipoint>& encryptedVotes, const std::vector<Scalar>& vote) const
 {
+    Proof retval;
+
     if (!malicious_client)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 bool PrsonaClient::verify_score_proof(const Proof& pi) const
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }

+ 3 - 2
prsona/src/main.cpp

@@ -198,8 +198,9 @@ int main(int argc, char *argv[])
 
     for (size_t i = 0; i < numRounds; i++)
     {
-        cout << "Round " << i+1 << " of " << numRounds << ": ";
-        cout << epoch(generator, servers, users, numVotesPerRound) << " seconds" << endl;
+        cout << "Round " << i+1 << " of " << numRounds << ": " << endl;
+        double timing = epoch(generator, servers, users, numVotesPerRound);
+        cout << "Server computation: " << timing << " seconds" << endl;
     }
 
     return 0;

+ 101 - 20
prsona/src/server.cpp

@@ -157,6 +157,18 @@ std::vector<Scalar> PrsonaServer::tally_scores(Proof& pi)
     return decryptedTallies;
 }
 
+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]);
+
+    Scalar retval = bgn_system.decrypt(currEncryptedVal);
+    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
 {
@@ -179,13 +191,19 @@ void PrsonaServer::import_updates(const Proof& pi, const std::vector<TwistBipoin
     voteMatrix = otherVoteMatrix;
 }
 
-void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies)
+void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies, std::vector<Scalar>& encryptedTallyMasks)
 {
     nextSeed.set_random();
     nextGenerator = nextGenerator * nextSeed;
 
     for (size_t i = 0; i < currentPseudonyms.size(); i++)
+    {
+        Scalar currMask;
+        currMask.set_random();
+
+        encryptedTallyMasks[i] = encryptedTallyMasks[i].curveAdd(currMask);
         currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
+    }   
         
     std::vector<size_t> shuffleOrder = order_data();
     rerandomize_vote_matrix();
@@ -198,22 +216,35 @@ void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vec
     pi = generate_proof_of_shuffle(shuffleOrder);
 }
 
-void PrsonaServer::epoch_part_two(Proof& pi, std::vector<EGCiphertext>& encryptedTallies)
+void PrsonaServer::epoch_part_two(Proof& pi, const Curvepoint& nextGenerator, std::vector<EGCiphertext>& encryptedTallies, std::vector<Scalar>& encryptedTallyMasks)
 {
     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);
     }
 
     std::vector<size_t> shuffleOrder = order_data();
     rerandomize_vote_matrix();
 
+    std::vector<Scalar> reorderedMasks;
     std::vector<EGCiphertext> reorderedTallies;
     for (size_t i = 0; i < shuffleOrder.size(); i++)
+    {
+        reorderedMasks.push_back(encryptedTallyMasks[shuffleOrder[i]]);
         reorderedTallies.push_back(encryptedTallies[shuffleOrder[i]]);
+    }
+    encryptedTallyMasks = reorderedMasks;
     encryptedTallies = reorderedTallies;
 
     pi = generate_proof_of_shuffle(shuffleOrder);
@@ -296,71 +327,121 @@ size_t PrsonaServer::binary_search(const Curvepoint& index) const
 bool PrsonaServer::verify_valid_key_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
 {
     if (!malicious_client)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "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.basic == "PROOF";
 
-    return pi == "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
 {
     if (!malicious_server)
-        return pi == "PROOF";
+        return pi.basic == "PROOF";
 
-    return pi == "PROOF";
+    return pi.basic == "PROOF";
 }
 
 Proof PrsonaServer::generate_valid_fresh_generator_proof(const Proof& oldProof) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServer::generate_votes_valid_proof(const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServer::generate_proof_of_added_user(const Curvepoint& shortTermPublicKey) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServer::generate_proof_of_correct_tally(const std::vector<Quadripoint>& BGNEncryptedTallies, const std::vector<Scalar>& decryptedTallies) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
+}
+
+Proof PrsonaServer::generate_proof_of_correct_sum(const TwistBipoint& BGNEncryptedSum, const Scalar& decryptedSum) const
+{
+    Proof retval;
+
+    if (!malicious_server)
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
+
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServer::generate_proof_of_shuffle(const std::vector<size_t>& shuffle_order) const
 {
+    Proof retval;
+
     if (!malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }

+ 85 - 26
prsona/src/serverEntity.cpp

@@ -2,6 +2,8 @@
 
 #include "serverEntity.hpp"
 
+const int maxAllowedVote = 3;
+
 PrsonaServerEntity::PrsonaServerEntity(size_t numServers)
 {
     if (numServers < 1)
@@ -67,8 +69,9 @@ void PrsonaServerEntity::add_new_client(PrsonaClient& newUser)
     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);
+    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);
 }
@@ -88,9 +91,13 @@ void PrsonaServerEntity::epoch()
     std::vector<Curvepoint> currentPseudonyms;
     std::vector<std::vector<CurveBipoint>> voteMatrix;
 
+    encryptedTallyMasks.clear();
+    for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
+        encryptedTallyMasks.push_back(Scalar());
+
     for (size_t i = 0; i < servers.size(); i++)
     {
-        servers[i].epoch_part_one(pi, nextGenerator, decryptedTalliedScores);
+        servers[i].epoch_part_one(pi, nextGenerator, decryptedTalliedScores, encryptedTallyMasks);
         servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
         if (i < servers.size() - 1)
             servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
@@ -102,13 +109,10 @@ void PrsonaServerEntity::epoch()
         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]);
+        encryptedTallies[i].mask = currentPseudonyms[i] * encryptedTallyMasks[i];
+        encryptedTallies[i].encryptedMessage = (nextGenerator * encryptedTallyMasks[i]) + (get_blinding_generator() * decryptedTalliedScores[i]);
     }
 
     pi = generate_epoch_round_one_proof(pi, proofOfCorrectTally);
@@ -116,7 +120,7 @@ void PrsonaServerEntity::epoch()
     
     for (size_t i = 0; i < servers.size(); i++)
     {
-        servers[i].epoch_part_two(pi, encryptedTallies);
+        servers[i].epoch_part_two(pi, nextGenerator, encryptedTallies, encryptedTallyMasks);
         servers[i].export_updates(previousVoteTally, currentPseudonyms, voteMatrix);
         if (i < servers.size() - 1)
             servers[i + 1].import_updates(pi, previousVoteTally, currentPseudonyms, voteMatrix);
@@ -138,65 +142,120 @@ void PrsonaServerEntity::transmit_score(PrsonaClient& newUser) const
     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);
+    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) const
+EGCiphertext PrsonaServerEntity::get_default_tally(Proof& pi, const Curvepoint& shortTermPublicKey, Scalar& randomizationMask) const
 {
     Proof unused;
     EGCiphertext retval;
 
-    Scalar lambda;
-    lambda.set_random();
+    randomizationMask.set_random();
 
-    retval.mask = shortTermPublicKey * lambda;
-    retval.encryptedMessage = get_fresh_generator(unused) * lambda + get_blinding_generator() * PrsonaServer::defaultTally;
+    retval.mask = shortTermPublicKey * randomizationMask;
+    retval.encryptedMessage = get_fresh_generator(unused) * randomizationMask + get_blinding_generator() * PrsonaServer::defaultTally;
 
-    pi = generate_valid_default_tally_proof(retval, lambda);
+    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)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServerEntity::generate_epoch_round_one_proof(const Proof& pi1, const Proof& pi2) const
 {
+    Proof retval;
+
     if (!PrsonaServer::malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
 Proof PrsonaServerEntity::generate_epoch_proof(const Proof& pi, const EGCiphertext& encryptedTally) const
 {
+    Proof retval;
+
     if (!PrsonaServer::malicious_server)
-        return "PROOF";
+    {
+        retval.basic = "PROOF";
+        return retval;
+    }
 
-    return "PROOF";
+    retval.basic = "PROOF";
+    return retval;
 }
 
-EGCiphertext PrsonaServerEntity::get_current_tally(Proof& pi, const Curvepoint& shortTermPublicKey) const
+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);
 
-    pi = tallyProofs[requester];
+    serverProof = tallyProofs[requester];
+
+    if (isOwner)
+        randomizationMask = encryptedTallyMasks[requester];
 
     return encryptedTallies[requester];
 }
 
 std::vector<Scalar> PrsonaServerEntity::tally_scores(Proof& pi)
 {
-    return servers[0].tally_scores(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;
 }
 
 size_t PrsonaServerEntity::binary_search(const Curvepoint& shortTermPublicKey) const