Browse Source

adding code into stubs, now missing proof stuff, ElGamal is probably not correct, no actual interaction between classes (that is, networking stuff to be added)

tristangurtler 3 years ago
parent
commit
33764d2df2
5 changed files with 302 additions and 38 deletions
  1. 9 0
      prsona/inc/EGCiphertext.hpp
  2. 30 10
      prsona/inc/client.hpp
  3. 34 8
      prsona/inc/server.hpp
  4. 67 10
      prsona/src/client.cpp
  5. 162 10
      prsona/src/server.cpp

+ 9 - 0
prsona/inc/EGCiphertext.hpp

@@ -0,0 +1,9 @@
+#ifndef __EG_CIPHERTEXT_HPP
+#define __EG_CIPHERTEXT_HPP
+
+struct EGCiphertext {    
+    Curvepoint mask;
+    Curvepoint encryptedMessage;
+}
+
+#endif

+ 30 - 10
prsona/inc/client.hpp

@@ -1,21 +1,41 @@
 #ifndef __PRSONA_CLIENT_HPP
 #define __PRSONA_CLIENT_HPP
 
+#include <unordered_map>
+
+#include "Curvepoint.hpp"
+#include "Scalar.hpp"
+#include "BGN.hpp"
+
 class PrsonaClient {
     public:
-        PrsonaClient();
-        void receive_score(Ciphertext score, Proof pi, Scalar newSeed);
-        void make_vote(vector<Scalar> vote);
-        void use_reputation();
-        bool verify_reputation_proof(Proof pi, PrsonaPublicKey shortTermPublicKey);
+        PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator);
+
+        Curvepoint get_long_term_public_key() const;
+        Curvepoint get_short_term_public_key() const;
+
+        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;
+        
+        Proof generate_reputation_proof() const;
+        bool verify_reputation_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const;
 
     private:
-        PrsonaPrivateKey longTermPrivateKey;
-        BGNPublicKey serverPublicKey;
-        Scalar currentFreshPseudonymSeed;
+        static const Curvepoint elGamalGenerator;
+        const Curvepoint elGamalBlindGenerator;
+        const BGNPublicKey serverPublicKey;
+        
+        Curvepoint currentFreshGenerator;
+        EGCiphertext currentEncryptedScore;
+
+        Scalar longTermPrivateKey;
+        Scalar currentScore;
+
+        Proof generate_vote_proof(const Scalar& vote) const;
+        bool verify_score_proof(const Proof& pi) const;
 
-        Proof generate_vote_proof(Scalar vote);
-        Proof generate_usage_proof();
+        std::unordered_map<Curvepoint, Scalar, CurvepointHash> decryption_memoizer;
+        Scalar max_checked;
 }; 
 
 #endif

+ 34 - 8
prsona/inc/server.hpp

@@ -1,23 +1,49 @@
 #ifndef __PRSONA_SERVER_HPP
 #define __PRSONA_SERVER_HPP
 
-class PrsonaServer {
+#include "BGN.hpp"
+#include "Curvepoint.hpp"
+#include "Bipoint.hpp"
+#include "EGCiphertext.hpp"
+
+class PrsonaServer : public BGN {
     public:
         PrsonaServer();
-        void add_new_client(PrsonaPublicKey longTermPublicKey);
-        void epoch();
-        void receive_vote(vector<CurveBipoint> vote, Proof pi, PrsonaPublicKey shortTermPublicKey);
+
+        Curvepoint get_blinding_generator() const;
+        Curvepoint get_fresh_generator() const;
+
+        Curvepoint add_new_client(const Curvepoint& longTermPublicKey);
+        vector<EGCiphertext> epoch();
+        void receive_vote(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey);
 
     private:
-        PrsonaPrivateKey longTermPrivateKey;
-        BGNPrivateKey bgnPrivateKey;
+        static const Curvepoint elGamalGenerator;
+        
+        Curvepoint elGamalBlindGenerator;
+
+        Scalar currentSeed;
+
         vector<TwistBipoint> previousVoteTally;
+        vector<Curvepoint> currentPseudonyms;
+        /* each element represents a vote by <rowID>
+         * applied to <colID> */
         vector<vector<CurveBipoint>> voteMatrix;
 
-        void calculate_vote_tally();
+        template <typename T>
+        void shuffle_vote_matrix(vector<T>& otherVector);
         void rerandomize_vote_matrix();
-        void distribute_new_scores();
+        
+        size_t binary_search(const Curvepoint& index) const;
         bool verify_vote_proof(CurveBipoint vote, Proof pi, PrsonaPublicKey shortTermPublicKey);
+
+        struct SortingType {
+            Curvepoint pseudonym;
+            size_t index;
+
+            bool operator<( const SortingType& rhs ) const
+                { return pseudonym < rhs.pseudonym; }
+        }
 }; 
 
 #endif

+ 67 - 10
prsona/src/client.cpp

@@ -1,36 +1,93 @@
 #include "client.hpp"
 
-PrsonaClient::PrsonaClient()
-{
+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);
 
+PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator)
+: serverPublicKey(serverPublicKey), elGamalBlindGenerator(elGamalBlindGenerator), max_checked(0)
+{
+    longTermPrivateKey.set_random();
+    decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
 }
 
-void PrsonaClient::receive_score(Ciphertext score, Proof pi, Scalar newSeed)
+Curvepoint PrsonaClient::get_long_term_public_key() const
 {
+    return elGamalGenerator * longTermPrivateKey;
+}
 
+Curvepoint PrsonaClient::get_short_term_public_key() const
+{
+    return currentFreshGenerator * longTermPrivateKey;
 }
 
-void PrsonaClient::make_vote(vector<Scalar> vote)
+void PrsonaClient::receive_score(const Proof& pi, const EGCiphertext& score, const Curvepoint& newGenerator)
 {
+    if (!verify_score_proof(pi))
+        return;
+
+    currentEncryptedScore = score;
+    currentFreshGenerator = newGenerator;
+
+    Curvepoint s, hashedDecrypted;
+    Scalar decryptionKey = scalarN - longTermPrivateKey;
+    s = currentEncryptedScore.mask * decryptionKey;
+    hashedDecrypted = currentEncryptedScore.encryptedMessage + s;
+    
+    auto lookup = decryption_memoizer.find(hashedDecrypted);
+    if (lookup != decryption_memoizer.end())
+    {
+        currentScore = lookup->second;
+        return;
+    }
+
+    max_checked++;
+    Curvepoint decryptionCandidate = elGamalBlindGenerator * max_checked;
+
+    while (decryptionCandidate != hashedDecrypted)
+    {
+        decryption_memoizer[decryptionCandidate] = max_checked;
 
+        decryptionCandidate = decryptionCandidate + elGamalBlindGenerator;
+        max_checked++;
+    }
+
+    curve_memoizer[decryptionCandidate] = max_checked;
+    currentScore = max_checked;
 }
 
-void PrsonaClient::use_reputation()
+void PrsonaClient::make_votes(vector<CurveBipoint>& encryptedVotes, vector<Proof>& validVoteProofs, const vector<Scalar>& vote) const
 {
+    encryptedVotes.clear();
+    validVoteProofs.clear();
+
+    for (size_t i = 0; i < vote.size(); i++)
+    {
+        CurveBipoint currScore;
+        serverPublicKey.encrypt(currScore, vote[i]);
 
+        encryptedVotes.push_back(currScore);
+        validVoteProofs.push_back(generate_vote_proof(vote[i], currScore));
+    }
 }
 
-bool PrsonaClient::verify_reputation_proof(Proof pi, PrsonaPublicKey shortTermPublicKey)
+Proof PrsonaClient::generate_reputation_proof() const
+{
+    
+}
+
+bool PrsonaClient::verify_reputation_proof(const Proof& pi, const PrsonaPublicKey& shortTermPublicKey) const
 {
 
 }
 
-Proof PrsonaClient::generate_vote_proof(Scalar vote)
+Proof PrsonaClient::generate_vote_proof(const Scalar& vote, const CurveBipoint& encryptedVote) const
 {
 
 }
 
-Proof PrsonaClient::generate_usage_proof()
+bool verify_score_proof(const Proof& pi) const
 {
-    
-}
+
+}

+ 162 - 10
prsona/src/server.cpp

@@ -1,41 +1,193 @@
 #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);
+
 PrsonaServer::PrsonaServer()
 {
+    Scalar lambda;
+    lambda.set_random();
+
+    elGamalBlindGenerator = elGamalGenerator * lambda;
 
+    currentSeed.set_random();
 }
 
-void PrsonaServer::add_new_client(PrsonaPublicKey longTermPublicKey)
+Curvepoint PrsonaServer::get_blinding_generator() const
 {
-
+    return elGamalBlindGenerator;
 }
 
-void PrsonaServer::epoch()
+Curvepoint PrsonaServer::get_fresh_generator() const
 {
-
+    return elGamalGenerator * currentSeed;
 }
 
-void PrsonaServer::receive_vote(vector<CurveBipoint> vote, Proof pi, PrsonaPublicKey shortTermPublicKey)
+Curvepoint PrsonaServer::add_new_client(const Curvepoint& longTermPublicKey)
 {
-
+    Curvepoint newPseudonym = longTermPublicKey * currentSeed;
+    currentPseudonyms.push_back(newPseudonym);
+
+    TwistBipoint newTalliedVote;
+    encrypt(newTalliedVote, Scalar(0));
+    previousVoteTally.push_back(newTalliedVote);
+
+    CurveBipoint defaultVote;
+    encrypt(defaultVote, Scalar(0));
+    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);
+    }
+
+    rerandomize(defaultVote);
+    newRow.push_back(defaultVote);
+    voteMatrix.push_back(newRow);
+
+    return newPseudonym;
 }
 
-void PrsonaServer::calculate_vote_tally()
+vector<EGCiphertext> PrsonaServer::epoch()
 {
+    Scalar inverseSeed = scalarN - currentSeed;
+    Scalar nextSeed;
+    nextSeed.set_random();
+
+    vector<Quadripoint> BGNEncryptedTallies;
+    vector<Scalar> decryptedTallies;
+    vector<EGCiphertext> EGEncryptedTallies(currentPseudonyms.size());
+    for (size_t i = 0; i < voteMatrix.size(); i++)
+    {
+        vector<Quadripoint> currTally;
+
+        for (size_t j = 0; j < previousVoteTally.size(); j++)
+        {
+            Quadripoint curr;
+            homomorphic_multiplication(curr, voteMatrix[j][i], previousVoteTally[j]);
+            currTally.push_back(curr);
+        }
+
+        BGNEncryptedTallies.push_back(std::accumulate(currTally.begin(), currTally.end(), Quadripoint()));
+    }
+    
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+    {
+        currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
+        decryptedTallies.push_back(decrypt(BGNEncryptedTallies[i]));
+    }
+    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]);
+        
+        EGEncryptedTallies[i].mask = currentPseudonyms[i] * currMask;
+        EGEncryptedTallies[i].encryptedMessage = (nextGenerator * currMask) + (elGamalBlindGenerator * decryptedTallies[i]);
+    }
+
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+    {
+        currentPseudonyms[i] = currentPseudonyms[i] * inverseSeed;
+        EGEncryptedTallies[i].mask = EGEncryptedTallies[i].mask * inverseSeed;
+    }
+    shuffle_vote_matrix(EGEncryptedTallies);
+
+    return EGEncryptedTallies;
+}
 
+template <typename T>
+void PrsonaServer::shuffle_vote_matrix(vector<T>& otherVector)
+{
+    vector<sorting_t> sortTracker;
+    for (size_t i = 0; i < currentPseudonyms.size(); i++)
+    {
+        sorting_t curr;
+        
+        curr.pseudonym = currentPseudonyms[i];
+        curr.index = i;
+
+        sortTracker.push_back(curr);
+    }
+
+    std::sort(sortTracker.begin(), sortTracker.end());
+
+    vector<Curvepoint> newPseudonyms;
+    vector<TwistBipoint> newVoteTallies;
+    vector<vector<CurveBipoint>> newVoteMatrix;
+    vector<T> newOtherVector;
+
+    for (size_t i = 0; i < currentPseudonyms.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;
+        for (size_t j = 0; j < currentPseudonyms.size(); j++)
+        {
+            currNewRow.push_back(voteMatrix[sortTracker[i].index][sortTracker[j].index]);
+        }
+        newVoteMatrix.push_back(currNewRow);
+    }
+
+    currentPseudonyms = newPseudonyms;
+    previousVoteTally = newVoteTallies;
+    voteMatrix = newVoteMatrix;
+    otherVector = newOtherVector;
+
+    rerandomize_vote_matrix();
 }
 
 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] = rerandomize(voteMatrix[i][j]);
+        }
+    }
 }
 
-void PrsonaServer::distribute_new_scores()
+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;
+    lo = 0;
+    hi = currentPseudonyms.size() - 1;
+
+    while (lo < hi)
+    {
+        size_t mid = (lo + hi) / 2;
+        if (currentPseudonyms[mid] < index)
+            lo = mid + 1;
+        else if (index == currentPseudonyms[mid])
+            return mid;
+        else hi = mid - 1;
+    }
+
+    return lo;
 }
 
-bool PrsonaServer::verify_vote_proof(CurveBipoint vote, Proof pi, PrsonaPublicKey shortTermPublicKey)
+bool PrsonaServer::verify_vote_proof(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
 {
 
 }