Browse Source

proof batching for 2/3 cases currently in place

tristangurtler 3 years ago
parent
commit
c36f40b878
6 changed files with 893 additions and 303 deletions
  1. 106 22
      prsona/inc/base.hpp
  2. 2 1
      prsona/inc/proof.hpp
  3. 749 272
      prsona/src/base.cpp
  4. 14 5
      prsona/src/localMain.cpp
  5. 14 3
      prsona/src/proof.cpp
  6. 8 0
      prsona/src/server.cpp

+ 106 - 22
prsona/inc/base.hpp

@@ -19,6 +19,7 @@ class PrsonaBase {
         static void init();
         static void set_server_malicious();
         static void set_client_malicious();
+        static void set_lambda(size_t lambda);
 
         // CONST GETTERS
         static size_t get_max_allowed_vote();
@@ -41,6 +42,7 @@ class PrsonaBase {
 
         static bool SERVER_IS_MALICIOUS;
         static bool CLIENT_IS_MALICIOUS;
+        static size_t LAMBDA;
         
         std::vector<Proof> elGamalBlindGeneratorProof;
         Twistpoint elGamalBlindGenerator;
@@ -164,6 +166,72 @@ class PrsonaBase {
             const std::vector<std::vector<Twistpoint>>& commits
         ) const;
 
+        template <typename T>
+        std::vector<Proof> generate_proof_of_reordering(
+            const std::vector<std::vector<Scalar>>& permutations,
+            const std::vector<std::vector<Scalar>>& permutationSeeds,
+            const std::vector<std::vector<Scalar>>& productSeeds,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
+        template <typename T>
+        bool verify_proof_of_reordering(
+            const std::vector<Proof>& pi,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
+        template <typename T>
+        std::vector<Proof> generate_unbatched_proof_of_reordering(
+            const std::vector<std::vector<Scalar>>& permutations,
+            const std::vector<std::vector<Scalar>>& permutationSeeds,
+            const std::vector<std::vector<Scalar>>& productSeeds,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
+        template <typename T>
+        bool verify_unbatched_proof_of_reordering(
+            const std::vector<Proof>& pi,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
+        template <typename T>
+        std::vector<Proof> generate_batched_proof_of_reordering(
+            const std::vector<std::vector<Scalar>>& permutations,
+            const std::vector<std::vector<Scalar>>& permutationSeeds,
+            const std::vector<std::vector<Scalar>>& productSeeds,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
+        template <typename T>
+        bool verify_batched_proof_of_reordering(
+            const std::vector<Proof>& pi,
+            const std::vector<T>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<T>>& productCommits,
+            const T& otherG,
+            const T& otherH
+        ) const;
+
         std::vector<Proof> generate_proof_of_reordering_plus_power(
             const std::vector<std::vector<Scalar>>& permutations,
             const Scalar& power,
@@ -183,6 +251,44 @@ class PrsonaBase {
             const std::vector<std::vector<Twistpoint>>& seedCommits
         ) const;
 
+        std::vector<Proof> generate_unbatched_proof_of_reordering_plus_power(
+            const std::vector<std::vector<Scalar>>& permutations,
+            const Scalar& power,
+            const std::vector<std::vector<Scalar>>& permutationSeeds,
+            const std::vector<std::vector<Scalar>>& productSeeds,
+            const std::vector<Twistpoint>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<Twistpoint>>& productCommits,
+            const std::vector<std::vector<Twistpoint>>& seedCommits
+        ) const;
+
+        bool verify_unbatched_proof_of_reordering_plus_power(
+            const std::vector<Proof>& pi,
+            const std::vector<Twistpoint>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<Twistpoint>>& productCommits,
+            const std::vector<std::vector<Twistpoint>>& seedCommits
+        ) const;
+
+        std::vector<Proof> generate_batched_proof_of_reordering_plus_power(
+            const std::vector<std::vector<Scalar>>& permutations,
+            const Scalar& power,
+            const std::vector<std::vector<Scalar>>& permutationSeeds,
+            const std::vector<std::vector<Scalar>>& productSeeds,
+            const std::vector<Twistpoint>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<Twistpoint>>& productCommits,
+            const std::vector<std::vector<Twistpoint>>& seedCommits
+        ) const;
+
+        bool verify_batched_proof_of_reordering_plus_power(
+            const std::vector<Proof>& pi,
+            const std::vector<Twistpoint>& oldValues,
+            const std::vector<std::vector<Twistpoint>>& permutationCommits,
+            const std::vector<std::vector<Twistpoint>>& productCommits,
+            const std::vector<std::vector<Twistpoint>>& seedCommits
+        ) const;
+
         std::vector<Proof> generate_user_tally_proofs(
             const std::vector<std::vector<Scalar>>& permutations,
             const Scalar& power,
@@ -210,28 +316,6 @@ class PrsonaBase {
             const std::vector<std::vector<Twistpoint>>& userTallySeedCommits
         ) const;
 
-        template <typename T>
-        std::vector<Proof> generate_proof_of_reordering(
-            const std::vector<std::vector<Scalar>>& permutations,
-            const std::vector<std::vector<Scalar>>& permutationSeeds,
-            const std::vector<std::vector<Scalar>>& productSeeds,
-            const std::vector<T>& oldValues,
-            const std::vector<std::vector<Twistpoint>>& permutationCommits,
-            const std::vector<std::vector<T>>& productCommits,
-            const T& otherG,
-            const T& otherH
-        ) const;
-
-        template <typename T>
-        bool verify_proof_of_reordering(
-            const std::vector<Proof>& pi,
-            const std::vector<T>& oldValues,
-            const std::vector<std::vector<Twistpoint>>& permutationCommits,
-            const std::vector<std::vector<T>>& productCommits,
-            const T& otherG,
-            const T& otherH
-        ) const;
-
         // SERVER AGREEMENT PROOFS
         Proof generate_valid_vote_row_proof(
             const std::vector<TwistBipoint>& commitment

+ 2 - 1
prsona/inc/proof.hpp

@@ -45,7 +45,8 @@ class Proof {
 };
 
 Scalar oracle(
-    const std::string& input);
+    const std::string& input,
+    size_t lambda_0 = 256);
 
 #endif
 

+ 749 - 272
prsona/src/base.cpp

@@ -10,14 +10,16 @@ extern const twistpoint_fp2_t bn_twistgen;
  * but in C++ putting code here doesn't actually execute
  * (or at least, with g++, whenever it would execute is not at a useful time)
  * so we have an init() function to actually put the correct values in them. */
+size_t PrsonaBase::MAX_ALLOWED_VOTE = 2;
 Twistpoint PrsonaBase::EL_GAMAL_GENERATOR = Twistpoint();
+
 Scalar PrsonaBase::SCALAR_N = Scalar();
 Scalar PrsonaBase::DEFAULT_TALLY = Scalar();
 Scalar PrsonaBase::DEFAULT_VOTE = Scalar();
 
 bool PrsonaBase::SERVER_IS_MALICIOUS = false;
 bool PrsonaBase::CLIENT_IS_MALICIOUS = false;
-size_t PrsonaBase::MAX_ALLOWED_VOTE = 2;
+size_t PrsonaBase::LAMBDA = 0;
 
 // Quick and dirty function to calculate ceil(log base 2) with mpz_class
 mpz_class log2(mpz_class x)
@@ -66,6 +68,12 @@ void PrsonaBase::set_client_malicious()
     CLIENT_IS_MALICIOUS = true;
 }
 
+// Call this (once) if using proof batching
+void PrsonaBase::set_lambda(size_t lambda)
+{
+    LAMBDA = lambda;
+}
+
 /*
  * CONST GETTERS
  */
@@ -941,15 +949,48 @@ bool PrsonaBase::verify_valid_permutation_proof(
     return true;
 }
 
-std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
+template <typename T>
+std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
     const std::vector<std::vector<Scalar>>& permutations,
-    const Scalar& power,
     const std::vector<std::vector<Scalar>>& permutationSeeds,
     const std::vector<std::vector<Scalar>>& productSeeds,
-    const std::vector<Twistpoint>& oldValues,
+    const std::vector<T>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<Twistpoint>>& productCommits,
-    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
+{
+    if (LAMBDA > 0)
+        return generate_batched_proof_of_reordering<T>(permutations, permutationSeeds, productSeeds, oldValues, permutationCommits, productCommits, otherG, otherH);
+    else
+        return generate_unbatched_proof_of_reordering<T>(permutations, permutationSeeds, productSeeds, oldValues, permutationCommits, productCommits, otherG, otherH);
+}
+
+template <typename T>
+bool PrsonaBase::verify_proof_of_reordering(
+    const std::vector<Proof>& pi,
+    const std::vector<T>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
+{
+    if (LAMBDA > 0)
+        return verify_batched_proof_of_reordering<T>(pi, oldValues, permutationCommits, productCommits, otherG, otherH);
+    else
+        return verify_unbatched_proof_of_reordering<T>(pi, oldValues, permutationCommits, productCommits, otherG, otherH);
+}
+
+template <typename T>
+std::vector<Proof> PrsonaBase::generate_unbatched_proof_of_reordering(
+    const std::vector<std::vector<Scalar>>& permutations,
+    const std::vector<std::vector<Scalar>>& permutationSeeds,
+    const std::vector<std::vector<Scalar>>& productSeeds,
+    const std::vector<T>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
 {
     std::vector<Proof> retval;
 
@@ -961,12 +1002,12 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
 
     Proof first;
     retval.push_back(first);
-    
+
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h;
+    oracleInput << g << h << otherG << otherH;
 
     for (size_t i = 0; i < oldValues.size(); i++)
         oracleInput << oldValues[i];
@@ -979,19 +1020,13 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
         for (size_t j = 0; j < productCommits[i].size(); j++)
             oracleInput << productCommits[i][j];
 
-    for (size_t i = 0; i < seedCommits.size(); i++)
-        for (size_t j = 0; j < seedCommits[i].size(); j++)
-            oracleInput << seedCommits[i][j];
-
-    Scalar b1;
-    b1.set_random();
-    std::vector<std::vector<Scalar>> b2;
+    std::vector<std::vector<Scalar>> a;
     std::vector<std::vector<Scalar>> t1;
     std::vector<std::vector<Scalar>> t2;
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
-        std::vector<Scalar> currb2Row;
+        std::vector<Scalar> curraRow;
         std::vector<Scalar> currt1Row;
         std::vector<Scalar> currt2Row;
 
@@ -999,34 +1034,30 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
         {
             Proof currProof;
 
-            Scalar currb2;
+            Scalar curra;
             Scalar currt1;
             Scalar currt2;
 
-            Twistpoint U1, U2, U3, U4;
+            Twistpoint U1;
+            T U2;
 
-            currb2.set_random();
+            curra.set_random();
             currt1.set_random();
             currt2.set_random();
 
-            U1 = g * currb2 + h * currt1;
-            U2 = oldValues[j] *
-                (b1 * permutations[j][i] + currb2 * power);
-            U3 = oldValues[j] * b1 * currb2 + h * currt2;
-            U4 = g * currt2;
-
-            currProof.curvepointUniversals.push_back(U2);
+            U1 = g * curra + h * currt1;
+            U2 = oldValues[j] * curra + otherH * currt2;
 
-            oracleInput << U1 << U2 << U3 << U4;
+            oracleInput << U1 << U2;
 
-            currb2Row.push_back(currb2);
+            curraRow.push_back(curra);
             currt1Row.push_back(currt1);
             currt2Row.push_back(currt2);
 
             retval.push_back(currProof);
         }
 
-        b2.push_back(currb2Row);
+        a.push_back(curraRow);
         t1.push_back(currt1Row);
         t2.push_back(currt2Row);
     }
@@ -1034,20 +1065,17 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
     Scalar x = oracle(oracleInput.str());
     retval[0].challengeParts.push_back(x);
 
-    Scalar f1 = power * x + b1;
-    retval[0].responseParts.push_back(f1);
-
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
         for (size_t j = 0; j < permutationCommits[i].size(); j++)
         {
             size_t piIndex = i * permutationCommits.size() + j + 1;
 
-            Scalar f2 = permutations[j][i] * x + b2[i][j];
+            Scalar f = permutations[j][i] * x + a[i][j];
             Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
-            Scalar z2 = productSeeds[i][j] * x * x + t2[i][j];
+            Scalar z2 = productSeeds[i][j] * x + t2[i][j];
 
-            retval[piIndex].responseParts.push_back(f2);
+            retval[piIndex].responseParts.push_back(f);
             retval[piIndex].responseParts.push_back(z1);
             retval[piIndex].responseParts.push_back(z2);
         }
@@ -1056,24 +1084,26 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
     return retval;
 }
 
-bool PrsonaBase::verify_proof_of_reordering_plus_power(
+template <typename T>
+bool PrsonaBase::verify_unbatched_proof_of_reordering(
     const std::vector<Proof>& pi,
-    const std::vector<Twistpoint>& oldValues,
+    const std::vector<T>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<Twistpoint>>& productCommits,
-    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
 {
     if (pi.empty())
         return false;
 
     if (!SERVER_IS_MALICIOUS)
         return pi[0].hbc == "PROOF";
-    
+
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h;
+    oracleInput << g << h << otherG << otherH;
 
     for (size_t i = 0; i < oldValues.size(); i++)
         oracleInput << oldValues[i];
@@ -1086,12 +1116,7 @@ bool PrsonaBase::verify_proof_of_reordering_plus_power(
         for (size_t j = 0; j < productCommits[i].size(); j++)
             oracleInput << productCommits[i][j];
 
-    for (size_t i = 0; i < seedCommits.size(); i++)
-        for (size_t j = 0; j < seedCommits[i].size(); j++)
-            oracleInput << seedCommits[i][j];
-
     Scalar x = pi[0].challengeParts[0];
-    Scalar f1 = pi[0].responseParts[0];
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
@@ -1099,62 +1124,44 @@ bool PrsonaBase::verify_proof_of_reordering_plus_power(
         {
             size_t piIndex = i * permutationCommits.size() + j + 1;
 
-            Twistpoint U1, U2, U3, U4;
-            U2 = pi[piIndex].curvepointUniversals[0];
+            Twistpoint U1;
+            T U2;
 
-            Scalar f2 = pi[piIndex].responseParts[0];
+            Scalar f = pi[piIndex].responseParts[0];
             Scalar z1 = pi[piIndex].responseParts[1];
             Scalar z2 = pi[piIndex].responseParts[2];
 
-            U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
+            U1 = g * f +
+                h * z1 -
+                permutationCommits[j][i] * x;
             
-            U3 = oldValues[j] * f1 * f2 +
-                h * z2 -
-                productCommits[i][j] * x * x -
-                U2 * x;
-
-            U4 = g * z2 - seedCommits[i][j] * x * x;
+            U2 = oldValues[j] * f +
+                otherH * z2 -
+                productCommits[i][j] * x;
 
-            oracleInput << U1 << U2 << U3 << U4;
+            oracleInput << U1 << U2;
         }
     }
 
     if (x != oracle(oracleInput.str()))
     {
-        std::cerr << "Reordered + power things not generated by permutation matrix." << std::endl;
+        std::cerr << "Reordered things not generated by permutation matrix." << std::endl;
         return false;
     }
 
-    for (size_t i = 0; i < seedCommits.size(); i++)
-    {
-        Twistpoint sum = seedCommits[i][0];
-
-        for (size_t j = 1; j < seedCommits[i].size(); j++)
-            sum = sum + seedCommits[i][j];
-
-        if (sum != Twistpoint())
-        {
-            std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
-            return false;
-        }
-    }
-
     return true;
 }
 
-std::vector<Proof> PrsonaBase::generate_user_tally_proofs(
+template <typename T>
+std::vector<Proof> PrsonaBase::generate_batched_proof_of_reordering(
     const std::vector<std::vector<Scalar>>& permutations,
-    const Scalar& power,
-    const Twistpoint& nextGenerator,
     const std::vector<std::vector<Scalar>>& permutationSeeds,
-    const std::vector<std::vector<Scalar>>& userTallySeeds,
-    const std::vector<Twistpoint>& currPseudonyms,
-    const std::vector<Twistpoint>& userTallyMasks,
-    const std::vector<Twistpoint>& userTallyMessages,
+    const std::vector<std::vector<Scalar>>& productSeeds,
+    const std::vector<T>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
 {
     std::vector<Proof> retval;
 
@@ -1166,240 +1173,190 @@ std::vector<Proof> PrsonaBase::generate_user_tally_proofs(
 
     Proof first;
     retval.push_back(first);
-    
+
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h << nextGenerator;
-
-    for (size_t i = 0; i < currPseudonyms.size(); i++)
-        oracleInput << currPseudonyms[i];
-
-    for (size_t i = 0; i < userTallyMasks.size(); i++)
-        oracleInput << userTallyMasks[i];
+    oracleInput << g << h << otherG << otherH;
 
-    for (size_t i = 0; i < userTallyMessages.size(); i++)
-        oracleInput << userTallyMessages[i];
+    for (size_t i = 0; i < oldValues.size(); i++)
+        oracleInput << oldValues[i];
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
         for (size_t j = 0; j < permutationCommits[i].size(); j++)
             oracleInput << permutationCommits[i][j];
 
-    for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
-        for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
-            oracleInput << userTallyMaskCommits[i][j];
-
-    for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
-        for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
-            oracleInput << userTallyMessageCommits[i][j];
-
-    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
-        for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
-            oracleInput << userTallySeedCommits[i][j];
+    for (size_t i = 0; i < productCommits.size(); i++)
+        for (size_t j = 0; j < productCommits[i].size(); j++)
+            oracleInput << productCommits[i][j];
 
-    Scalar b1;
-    b1.set_random();
-    std::vector<std::vector<Scalar>> b2;
-    std::vector<std::vector<Scalar>> t1;
-    std::vector<std::vector<Scalar>> t2;
+    std::vector<Scalar> a;
+    std::vector<Scalar> t1;
+    std::vector<Scalar> t2;
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
-        std::vector<Scalar> currb2Row;
-        std::vector<Scalar> currt1Row;
-        std::vector<Scalar> currt2Row;
-
-        for (size_t j = 0; j < permutationCommits[i].size(); j++)
-        {
-            Proof currProof;
-
-            Scalar currb2;
-            Scalar currt1;
-            Scalar currt2;
-
-            Twistpoint U1, U2, U3, U4, U5, U6, U7;
+        Proof currProof;
 
-            currb2.set_random();
-            currt1.set_random();
-            currt2.set_random();
+        Scalar curra;
+        Scalar currt1;
+        Scalar currt2;
 
-            U1 = g * currb2 + h * currt1;
-            U2 = userTallyMasks[j] * (b1 * permutations[j][i] + currb2 * power) +
-                currPseudonyms[j] * (permutations[j][i] * b1 * userTallySeeds[i][j] + power * currb2 * userTallySeeds[i][j] + permutations[j][i] * power * currt2) +
-                h * currt2;
-            U3 = userTallyMasks[j] * (b1 * currb2) +
-                currPseudonyms[j] * (b1 * currb2 * userTallySeeds[i][j] + permutations[j][i] * b1 * currt2 + power * currb2 * currt2);
-            U4 = currPseudonyms[j] * (b1 * currb2 * currt2);
-            U5 = userTallyMessages[j] * currb2 +
-                nextGenerator * (permutations[j][i] * currt2 + userTallySeeds[i][j] * currb2) +
-                h * currt2;
-            U6 = nextGenerator * (currb2 * currt2);
-            U7 = g * currt2;
+        Twistpoint U1;
+        T U2;
 
-            currProof.curvepointUniversals.push_back(U2);
-            currProof.curvepointUniversals.push_back(U3);
-            currProof.curvepointUniversals.push_back(U5);
+        curra.set_random();
+        currt1.set_random();
+        currt2.set_random();
 
-            oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
+        U1 = g * curra + h * currt1;
+        U2 = oldValues[i] * curra + otherH * currt2;
 
-            currb2Row.push_back(currb2);
-            currt1Row.push_back(currt1);
-            currt2Row.push_back(currt2);
+        oracleInput << U1 << U2;
 
-            retval.push_back(currProof);
-        }
+        a.push_back(curra);
+        t1.push_back(currt1);
+        t2.push_back(currt2);
 
-        b2.push_back(currb2Row);
-        t1.push_back(currt1Row);
-        t2.push_back(currt2Row);
+        retval.push_back(currProof);
     }
 
     Scalar x = oracle(oracleInput.str());
     retval[0].challengeParts.push_back(x);
 
-    Scalar f1 = power * x + b1;
-    retval[0].responseParts.push_back(f1);
-
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
+        size_t piIndex = i + 1;
+
+        Scalar f = a[i];
+        Scalar z1 = t1[i];
+        Scalar z2 = t2[i];
+
         for (size_t j = 0; j < permutationCommits[i].size(); j++)
         {
-            size_t piIndex = i * permutationCommits.size() + j + 1;
-
-            Scalar f2 = permutations[j][i] * x + b2[i][j];
-            Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
-            Scalar z2 = userTallySeeds[i][j] * x + t2[i][j];
+            std::stringstream currOracle;
+            currOracle << permutationCommits[i][j] << productCommits[j][i];
+            Scalar currx = oracle(currOracle.str(), LAMBDA);
 
-            retval[piIndex].responseParts.push_back(f2);
-            retval[piIndex].responseParts.push_back(z1);
-            retval[piIndex].responseParts.push_back(z2);
+            f = f + permutations[i][j] * currx;
+            z1 = z1 + permutationSeeds[i][j] * currx;
+            z2 = z2 + productSeeds[j][i] * currx;
         }
+
+        retval[piIndex].responseParts.push_back(f);
+        retval[piIndex].responseParts.push_back(z1);
+        retval[piIndex].responseParts.push_back(z2);
     }
 
     return retval;
 }
 
-bool PrsonaBase::verify_user_tally_proofs(
+template <typename T>
+bool PrsonaBase::verify_batched_proof_of_reordering(
     const std::vector<Proof>& pi,
-    const Twistpoint& nextGenerator,
-    const std::vector<Twistpoint>& currPseudonyms,
-    const std::vector<Twistpoint>& userTallyMasks,
-    const std::vector<Twistpoint>& userTallyMessages,
+    const std::vector<T>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
-    const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
-{
+    const std::vector<std::vector<T>>& productCommits,
+    const T& otherG,
+    const T& otherH) const
+{
     if (pi.empty())
         return false;
 
     if (!SERVER_IS_MALICIOUS)
         return pi[0].hbc == "PROOF";
-    
+
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h << nextGenerator;
-
-    for (size_t i = 0; i < currPseudonyms.size(); i++)
-        oracleInput << currPseudonyms[i];
-
-    for (size_t i = 0; i < userTallyMasks.size(); i++)
-        oracleInput << userTallyMasks[i];
+    oracleInput << g << h << otherG << otherH;
 
-    for (size_t i = 0; i < userTallyMessages.size(); i++)
-        oracleInput << userTallyMessages[i];
+    for (size_t i = 0; i < oldValues.size(); i++)
+        oracleInput << oldValues[i];
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
         for (size_t j = 0; j < permutationCommits[i].size(); j++)
             oracleInput << permutationCommits[i][j];
 
-    for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
-        for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
-            oracleInput << userTallyMaskCommits[i][j];
-
-    for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
-        for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
-            oracleInput << userTallyMessageCommits[i][j];
-
-    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
-        for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
-            oracleInput << userTallySeedCommits[i][j];
+    for (size_t i = 0; i < productCommits.size(); i++)
+        for (size_t j = 0; j < productCommits[i].size(); j++)
+            oracleInput << productCommits[i][j];
 
     Scalar x = pi[0].challengeParts[0];
-    Scalar f1 = pi[0].responseParts[0];
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
-        for (size_t j = 0; j < permutationCommits[i].size(); j++)
-        {
-            size_t piIndex = i * permutationCommits.size() + j + 1;
+        size_t piIndex = i + 1;
 
-            Twistpoint U1, U2, U3, U4, U5, U6, U7;
-            U2 = pi[piIndex].curvepointUniversals[0];
-            U3 = pi[piIndex].curvepointUniversals[1];
-            U5 = pi[piIndex].curvepointUniversals[2];
+        Scalar f = pi[piIndex].responseParts[0];
+        Scalar z1 = pi[piIndex].responseParts[1];
+        Scalar z2 = pi[piIndex].responseParts[2];
 
-            Scalar f2 = pi[piIndex].responseParts[0];
-            Scalar z1 = pi[piIndex].responseParts[1];
-            Scalar z2 = pi[piIndex].responseParts[2];
+        Twistpoint U1 = g * f + h * z1;
+        T U2 = oldValues[i] * f + otherH * z2;
 
-            U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            std::stringstream currOracle;
+            currOracle << permutationCommits[i][j] << productCommits[j][i];
+            Scalar currx = oracle(currOracle.str(), LAMBDA);
             
-            U4 = userTallyMasks[j] * (f1 * f2 * x) +
-                currPseudonyms[j] * (f1 * f2 * z2) +
-                h * (z2 * x * x) -
-                userTallyMaskCommits[i][j] * (x * x * x) -
-                U2 * (x * x) -
-                U3 * x;
-
-            U6 = userTallyMessages[j] * (f2 * x) +
-                nextGenerator * (f2 * z2) +
-                h * (z2 * x) -
-                userTallyMessageCommits[i][j] * (x * x) -
-                U5 * x;
-
-            U7 = g * z2 - userTallySeedCommits[i][j] * x;
-
-            oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
+            U1 = U1 - permutationCommits[i][j] * currx;
+            U2 = U2 - productCommits[j][i] * currx;
         }
+
+        oracleInput << U1 << U2;
     }
 
     if (x != oracle(oracleInput.str()))
     {
-        std::cerr << "User tallies not generated by permutation matrix." << std::endl;
+        std::cerr << "Reordered things not generated by permutation matrix." << std::endl;
         return false;
     }
 
-    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
-    {
-        Twistpoint sum = userTallySeedCommits[i][0];
-
-        for (size_t j = 1; j < userTallySeedCommits[i].size(); j++)
-            sum = sum + userTallySeedCommits[i][j];
+    return true;
+}
 
-        if (sum != Twistpoint())
-        {
-            std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
-            return false;
-        }
-    }
+std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
+    const std::vector<std::vector<Scalar>>& permutations,
+    const Scalar& power,
+    const std::vector<std::vector<Scalar>>& permutationSeeds,
+    const std::vector<std::vector<Scalar>>& productSeeds,
+    const std::vector<Twistpoint>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+{
+    if (LAMBDA > 0)
+        return generate_batched_proof_of_reordering_plus_power(permutations, power, permutationSeeds, productSeeds, oldValues, permutationCommits, productCommits, seedCommits);
+    else
+        return generate_unbatched_proof_of_reordering_plus_power(permutations, power, permutationSeeds, productSeeds, oldValues, permutationCommits, productCommits, seedCommits);
+}
 
-    return true;
+bool PrsonaBase::verify_proof_of_reordering_plus_power(
+    const std::vector<Proof>& pi,
+    const std::vector<Twistpoint>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+{
+    if (LAMBDA > 0)
+        return verify_batched_proof_of_reordering_plus_power(pi, oldValues, permutationCommits, productCommits, seedCommits);
+    else
+        return verify_unbatched_proof_of_reordering_plus_power(pi, oldValues, permutationCommits, productCommits, seedCommits);
 }
 
-template <typename T>
-std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
+std::vector<Proof> PrsonaBase::generate_unbatched_proof_of_reordering_plus_power(
     const std::vector<std::vector<Scalar>>& permutations,
+    const Scalar& power,
     const std::vector<std::vector<Scalar>>& permutationSeeds,
     const std::vector<std::vector<Scalar>>& productSeeds,
-    const std::vector<T>& oldValues,
+    const std::vector<Twistpoint>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<T>>& productCommits,
-    const T& otherG,
-    const T& otherH) const
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
 {
     std::vector<Proof> retval;
 
@@ -1411,12 +1368,12 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
 
     Proof first;
     retval.push_back(first);
-
+    
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h << otherG << otherH;
+    oracleInput << g << h;
 
     for (size_t i = 0; i < oldValues.size(); i++)
         oracleInput << oldValues[i];
@@ -1429,13 +1386,19 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
         for (size_t j = 0; j < productCommits[i].size(); j++)
             oracleInput << productCommits[i][j];
 
-    std::vector<std::vector<Scalar>> a;
+    for (size_t i = 0; i < seedCommits.size(); i++)
+        for (size_t j = 0; j < seedCommits[i].size(); j++)
+            oracleInput << seedCommits[i][j];
+
+    Scalar b1;
+    b1.set_random();
+    std::vector<std::vector<Scalar>> b2;
     std::vector<std::vector<Scalar>> t1;
     std::vector<std::vector<Scalar>> t2;
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
-        std::vector<Scalar> curraRow;
+        std::vector<Scalar> currb2Row;
         std::vector<Scalar> currt1Row;
         std::vector<Scalar> currt2Row;
 
@@ -1443,30 +1406,34 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
         {
             Proof currProof;
 
-            Scalar curra;
+            Scalar currb2;
             Scalar currt1;
             Scalar currt2;
 
-            Twistpoint U1;
-            T U2;
+            Twistpoint U1, U2, U3, U4;
 
-            curra.set_random();
+            currb2.set_random();
             currt1.set_random();
             currt2.set_random();
 
-            U1 = g * curra + h * currt1;
-            U2 = oldValues[j] * curra + otherH * currt2;
+            U1 = g * currb2 + h * currt1;
+            U2 = oldValues[j] *
+                (b1 * permutations[j][i] + currb2 * power);
+            U3 = oldValues[j] * b1 * currb2 + h * currt2;
+            U4 = g * currt2;
 
-            oracleInput << U1 << U2;
+            currProof.curvepointUniversals.push_back(U2);
 
-            curraRow.push_back(curra);
+            oracleInput << U1 << U2 << U3 << U4;
+
+            currb2Row.push_back(currb2);
             currt1Row.push_back(currt1);
             currt2Row.push_back(currt2);
 
             retval.push_back(currProof);
         }
 
-        a.push_back(curraRow);
+        b2.push_back(currb2Row);
         t1.push_back(currt1Row);
         t2.push_back(currt2Row);
     }
@@ -1474,17 +1441,20 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
     Scalar x = oracle(oracleInput.str());
     retval[0].challengeParts.push_back(x);
 
+    Scalar f1 = power * x + b1;
+    retval[0].responseParts.push_back(f1);
+
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
         for (size_t j = 0; j < permutationCommits[i].size(); j++)
         {
             size_t piIndex = i * permutationCommits.size() + j + 1;
 
-            Scalar f = permutations[j][i] * x + a[i][j];
+            Scalar f2 = permutations[j][i] * x + b2[i][j];
             Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
-            Scalar z2 = productSeeds[i][j] * x + t2[i][j];
+            Scalar z2 = productSeeds[i][j] * x * x + t2[i][j];
 
-            retval[piIndex].responseParts.push_back(f);
+            retval[piIndex].responseParts.push_back(f2);
             retval[piIndex].responseParts.push_back(z1);
             retval[piIndex].responseParts.push_back(z2);
         }
@@ -1493,26 +1463,24 @@ std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
     return retval;
 }
 
-template <typename T>
-bool PrsonaBase::verify_proof_of_reordering(
+bool PrsonaBase::verify_unbatched_proof_of_reordering_plus_power(
     const std::vector<Proof>& pi,
-    const std::vector<T>& oldValues,
+    const std::vector<Twistpoint>& oldValues,
     const std::vector<std::vector<Twistpoint>>& permutationCommits,
-    const std::vector<std::vector<T>>& productCommits,
-    const T& otherG,
-    const T& otherH) const
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
 {
     if (pi.empty())
         return false;
 
     if (!SERVER_IS_MALICIOUS)
         return pi[0].hbc == "PROOF";
-
+    
     Twistpoint g = EL_GAMAL_GENERATOR;
     Twistpoint h = elGamalBlindGenerator;
 
     std::stringstream oracleInput;
-    oracleInput << g << h << otherG << otherH;
+    oracleInput << g << h;
 
     for (size_t i = 0; i < oldValues.size(); i++)
         oracleInput << oldValues[i];
@@ -1525,7 +1493,12 @@ bool PrsonaBase::verify_proof_of_reordering(
         for (size_t j = 0; j < productCommits[i].size(); j++)
             oracleInput << productCommits[i][j];
 
+    for (size_t i = 0; i < seedCommits.size(); i++)
+        for (size_t j = 0; j < seedCommits[i].size(); j++)
+            oracleInput << seedCommits[i][j];
+
     Scalar x = pi[0].challengeParts[0];
+    Scalar f1 = pi[0].responseParts[0];
 
     for (size_t i = 0; i < permutationCommits.size(); i++)
     {
@@ -1533,31 +1506,535 @@ bool PrsonaBase::verify_proof_of_reordering(
         {
             size_t piIndex = i * permutationCommits.size() + j + 1;
 
-            Twistpoint U1;
-            T U2;
+            Twistpoint U1, U2, U3, U4;
+            U2 = pi[piIndex].curvepointUniversals[0];
 
-            Scalar f = pi[piIndex].responseParts[0];
+            Scalar f2 = pi[piIndex].responseParts[0];
             Scalar z1 = pi[piIndex].responseParts[1];
             Scalar z2 = pi[piIndex].responseParts[2];
 
-            U1 = g * f +
-                h * z1 -
-                permutationCommits[j][i] * x;
+            U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
             
-            U2 = oldValues[j] * f +
-                otherH * z2 -
-                productCommits[i][j] * x;
+            U3 = oldValues[j] * f1 * f2 +
+                h * z2 -
+                productCommits[i][j] * x * x -
+                U2 * x;
 
-            oracleInput << U1 << U2;
+            U4 = g * z2 - seedCommits[i][j] * x * x;
+
+            oracleInput << U1 << U2 << U3 << U4;
         }
     }
 
     if (x != oracle(oracleInput.str()))
     {
-        std::cerr << "Reordered things not generated by permutation matrix." << std::endl;
+        std::cerr << "Reordered + power things not generated by permutation matrix." << std::endl;
         return false;
     }
 
+    for (size_t i = 0; i < seedCommits.size(); i++)
+    {
+        Twistpoint sum = seedCommits[i][0];
+
+        for (size_t j = 1; j < seedCommits[i].size(); j++)
+            sum = sum + seedCommits[i][j];
+
+        if (sum != Twistpoint())
+        {
+            std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+std::vector<Proof> PrsonaBase::generate_batched_proof_of_reordering_plus_power(
+    const std::vector<std::vector<Scalar>>& permutations,
+    const Scalar& power,
+    const std::vector<std::vector<Scalar>>& permutationSeeds,
+    const std::vector<std::vector<Scalar>>& productSeeds,
+    const std::vector<Twistpoint>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+{
+    std::vector<Proof> retval;
+
+    if (!SERVER_IS_MALICIOUS)
+    {
+        retval.push_back(Proof("PROOF"));
+        return retval;
+    }
+
+    Proof first;
+    retval.push_back(first);
+    
+    Twistpoint g = EL_GAMAL_GENERATOR;
+    Twistpoint h = elGamalBlindGenerator;
+
+    std::stringstream oracleInput;
+    oracleInput << g << h;
+
+    for (size_t i = 0; i < oldValues.size(); i++)
+        oracleInput << oldValues[i];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            oracleInput << permutationCommits[i][j];
+
+    for (size_t i = 0; i < productCommits.size(); i++)
+        for (size_t j = 0; j < productCommits[i].size(); j++)
+            oracleInput << productCommits[i][j];
+
+    for (size_t i = 0; i < seedCommits.size(); i++)
+        for (size_t j = 0; j < seedCommits[i].size(); j++)
+            oracleInput << seedCommits[i][j];
+
+    std::vector<Scalar> b1;
+    std::vector<Scalar> b2;
+    std::vector<std::vector<Scalar>> b3;
+    std::vector<Scalar> t1;
+    std::vector<Scalar> t2;
+    std::vector<Scalar> t3;
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        Proof currProof;
+
+        Scalar currb1;
+        Scalar currb2;
+        std::vector<Scalar> currb3Row;
+        Scalar currt1;
+        Scalar currt2;
+        Scalar currt3;
+
+        Twistpoint U1, U3, U4;
+        std::vector<Twistpoint> U2;
+
+        currb1.set_random();
+        currb2.set_random();
+        currt1.set_random();
+        currt2.set_random();
+        currt3.set_random();
+
+        U1 = g * currb2 + h * currt1;
+        U3 = oldValues[i] * (currb1 * currb2 + currt3) + h * currt2;
+        U4 = g * currt2;
+
+        oracleInput << U1;
+
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            Twistpoint U2;
+            Scalar currb3;
+            currb3.set_random();
+            
+            Scalar U2mult = (currb1 * permutations[i][j] + currb2 * power + currb3);
+            for (size_t k = 0; k < permutationCommits[i].size(); k++)
+            {
+                if (k == j)
+                    continue;
+
+                std::stringstream currOracle;
+                currOracle << permutationCommits[i][k] << productCommits[k][i] << seedCommits[k][i];
+                Scalar currx = oracle(currOracle.str(), LAMBDA);
+
+                U2mult = U2mult + power * permutations[i][j] * currx;
+            }
+            U2 = oldValues[i] * U2mult;
+            currProof.curvepointUniversals.push_back(U2);
+
+            oracleInput << U2;
+
+            currb3Row.push_back(currb3);
+        }
+        oracleInput << U3 << U4;
+
+        b1.push_back(currb1);
+        b2.push_back(currb2);
+        b3.push_back(currb3Row);
+        t1.push_back(currt1);
+        t2.push_back(currt2);
+        t3.push_back(currt3);
+
+        retval.push_back(currProof);
+    }
+
+    Scalar x = oracle(oracleInput.str());
+    retval[0].challengeParts.push_back(x);
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        size_t piIndex = i + 1;
+
+        Scalar f1 = b1[i];
+        Scalar f2 = b2[i];
+        Scalar z1 = t1[i];
+        Scalar z2 = t2[i];
+        Scalar z3 = t3[i];
+
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            std::stringstream currOracle;
+            currOracle << permutationCommits[i][j] << productCommits[j][i] << seedCommits[j][i];
+            Scalar currx = oracle(currOracle.str(), LAMBDA);
+
+            f1 = f1 + power * currx;
+            f2 = f2 + permutations[i][j] * currx;
+            z1 = z1 + permutationSeeds[i][j] * currx;
+            z2 = z2 + productSeeds[j][i] * currx * currx;
+            z3 = z3 + b3[i][j] * currx;
+        }
+
+        retval[piIndex].responseParts.push_back(f1);
+        retval[piIndex].responseParts.push_back(f2);
+        retval[piIndex].responseParts.push_back(z1);
+        retval[piIndex].responseParts.push_back(z2);
+        retval[piIndex].responseParts.push_back(z3);
+    }
+
+    return retval;
+}
+
+bool PrsonaBase::verify_batched_proof_of_reordering_plus_power(
+    const std::vector<Proof>& pi,
+    const std::vector<Twistpoint>& oldValues,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& productCommits,
+    const std::vector<std::vector<Twistpoint>>& seedCommits) const
+{
+    if (pi.empty())
+        return false;
+
+    if (!SERVER_IS_MALICIOUS)
+        return pi[0].hbc == "PROOF";
+    
+    Twistpoint g = EL_GAMAL_GENERATOR;
+    Twistpoint h = elGamalBlindGenerator;
+
+    std::stringstream oracleInput;
+    oracleInput << g << h;
+
+    for (size_t i = 0; i < oldValues.size(); i++)
+        oracleInput << oldValues[i];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            oracleInput << permutationCommits[i][j];
+
+    for (size_t i = 0; i < productCommits.size(); i++)
+        for (size_t j = 0; j < productCommits[i].size(); j++)
+            oracleInput << productCommits[i][j];
+
+    for (size_t i = 0; i < seedCommits.size(); i++)
+        for (size_t j = 0; j < seedCommits[i].size(); j++)
+            oracleInput << seedCommits[i][j];
+
+    Scalar x = pi[0].challengeParts[0];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        size_t piIndex = i + 1;
+
+        Scalar f1 = pi[piIndex].responseParts[0];
+        Scalar f2 = pi[piIndex].responseParts[1];
+        Scalar z1 = pi[piIndex].responseParts[2];
+        Scalar z2 = pi[piIndex].responseParts[3];
+        Scalar z3 = pi[piIndex].responseParts[4];
+
+        Twistpoint U1 = g * f2 + h * z1;
+        std::vector<Twistpoint> U2 = pi[piIndex].curvepointUniversals;
+        Twistpoint U3 = oldValues[i] * (f1 * f2 + z3) + h * z2;
+        Twistpoint U4 = g * z2;
+
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            std::stringstream currOracle;
+            currOracle << permutationCommits[i][j] << productCommits[j][i] << seedCommits[j][i];
+            Scalar currx = oracle(currOracle.str(), LAMBDA);
+        
+            U1 = U1 - permutationCommits[i][j] * currx;
+            U3 = U3 -
+                productCommits[j][i] * currx * currx -
+                U2[j] * currx;
+            U4 = U4 - seedCommits[j][i] * currx * currx;
+        }
+
+        oracleInput << U1;
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            oracleInput << U2[j];
+        oracleInput << U3 << U4;
+    }
+
+    if (x != oracle(oracleInput.str()))
+    {
+        std::cerr << "Reordered + power things not generated by permutation matrix." << std::endl;
+        return false;
+    }
+
+    for (size_t i = 0; i < seedCommits.size(); i++)
+    {
+        Twistpoint sum = seedCommits[i][0];
+
+        for (size_t j = 1; j < seedCommits[i].size(); j++)
+            sum = sum + seedCommits[i][j];
+
+        if (sum != Twistpoint())
+        {
+            std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+std::vector<Proof> PrsonaBase::generate_user_tally_proofs(
+    const std::vector<std::vector<Scalar>>& permutations,
+    const Scalar& power,
+    const Twistpoint& nextGenerator,
+    const std::vector<std::vector<Scalar>>& permutationSeeds,
+    const std::vector<std::vector<Scalar>>& userTallySeeds,
+    const std::vector<Twistpoint>& currPseudonyms,
+    const std::vector<Twistpoint>& userTallyMasks,
+    const std::vector<Twistpoint>& userTallyMessages,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
+{
+    std::vector<Proof> retval;
+
+    if (!SERVER_IS_MALICIOUS)
+    {
+        retval.push_back(Proof("PROOF"));
+        return retval;
+    }
+
+    Proof first;
+    retval.push_back(first);
+    
+    Twistpoint g = EL_GAMAL_GENERATOR;
+    Twistpoint h = elGamalBlindGenerator;
+
+    std::stringstream oracleInput;
+    oracleInput << g << h << nextGenerator;
+
+    for (size_t i = 0; i < currPseudonyms.size(); i++)
+        oracleInput << currPseudonyms[i];
+
+    for (size_t i = 0; i < userTallyMasks.size(); i++)
+        oracleInput << userTallyMasks[i];
+
+    for (size_t i = 0; i < userTallyMessages.size(); i++)
+        oracleInput << userTallyMessages[i];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            oracleInput << permutationCommits[i][j];
+
+    for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
+            oracleInput << userTallyMaskCommits[i][j];
+
+    for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
+            oracleInput << userTallyMessageCommits[i][j];
+
+    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
+        for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
+            oracleInput << userTallySeedCommits[i][j];
+
+    Scalar b1;
+    b1.set_random();
+    std::vector<std::vector<Scalar>> b2;
+    std::vector<std::vector<Scalar>> t1;
+    std::vector<std::vector<Scalar>> t2;
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        std::vector<Scalar> currb2Row;
+        std::vector<Scalar> currt1Row;
+        std::vector<Scalar> currt2Row;
+
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            Proof currProof;
+
+            Scalar currb2;
+            Scalar currt1;
+            Scalar currt2;
+
+            Twistpoint U1, U2, U3, U4, U5, U6, U7;
+
+            currb2.set_random();
+            currt1.set_random();
+            currt2.set_random();
+
+            U1 = g * currb2 + h * currt1;
+            U2 = userTallyMasks[j] * (b1 * permutations[j][i] + currb2 * power) +
+                currPseudonyms[j] * (permutations[j][i] * b1 * userTallySeeds[i][j] + power * currb2 * userTallySeeds[i][j] + permutations[j][i] * power * currt2) +
+                h * currt2;
+            U3 = userTallyMasks[j] * (b1 * currb2) +
+                currPseudonyms[j] * (b1 * currb2 * userTallySeeds[i][j] + permutations[j][i] * b1 * currt2 + power * currb2 * currt2);
+            U4 = currPseudonyms[j] * (b1 * currb2 * currt2);
+            U5 = userTallyMessages[j] * currb2 +
+                nextGenerator * (permutations[j][i] * currt2 + userTallySeeds[i][j] * currb2) +
+                h * currt2;
+            U6 = nextGenerator * (currb2 * currt2);
+            U7 = g * currt2;
+
+            currProof.curvepointUniversals.push_back(U2);
+            currProof.curvepointUniversals.push_back(U3);
+            currProof.curvepointUniversals.push_back(U5);
+
+            oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
+
+            currb2Row.push_back(currb2);
+            currt1Row.push_back(currt1);
+            currt2Row.push_back(currt2);
+
+            retval.push_back(currProof);
+        }
+
+        b2.push_back(currb2Row);
+        t1.push_back(currt1Row);
+        t2.push_back(currt2Row);
+    }
+
+    Scalar x = oracle(oracleInput.str());
+    retval[0].challengeParts.push_back(x);
+
+    Scalar f1 = power * x + b1;
+    retval[0].responseParts.push_back(f1);
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            size_t piIndex = i * permutationCommits.size() + j + 1;
+
+            Scalar f2 = permutations[j][i] * x + b2[i][j];
+            Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
+            Scalar z2 = userTallySeeds[i][j] * x + t2[i][j];
+
+            retval[piIndex].responseParts.push_back(f2);
+            retval[piIndex].responseParts.push_back(z1);
+            retval[piIndex].responseParts.push_back(z2);
+        }
+    }
+
+    return retval;
+}
+
+bool PrsonaBase::verify_user_tally_proofs(
+    const std::vector<Proof>& pi,
+    const Twistpoint& nextGenerator,
+    const std::vector<Twistpoint>& currPseudonyms,
+    const std::vector<Twistpoint>& userTallyMasks,
+    const std::vector<Twistpoint>& userTallyMessages,
+    const std::vector<std::vector<Twistpoint>>& permutationCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
+    const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
+{
+    if (pi.empty())
+        return false;
+
+    if (!SERVER_IS_MALICIOUS)
+        return pi[0].hbc == "PROOF";
+    
+    Twistpoint g = EL_GAMAL_GENERATOR;
+    Twistpoint h = elGamalBlindGenerator;
+
+    std::stringstream oracleInput;
+    oracleInput << g << h << nextGenerator;
+
+    for (size_t i = 0; i < currPseudonyms.size(); i++)
+        oracleInput << currPseudonyms[i];
+
+    for (size_t i = 0; i < userTallyMasks.size(); i++)
+        oracleInput << userTallyMasks[i];
+
+    for (size_t i = 0; i < userTallyMessages.size(); i++)
+        oracleInput << userTallyMessages[i];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+            oracleInput << permutationCommits[i][j];
+
+    for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
+            oracleInput << userTallyMaskCommits[i][j];
+
+    for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
+        for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
+            oracleInput << userTallyMessageCommits[i][j];
+
+    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
+        for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
+            oracleInput << userTallySeedCommits[i][j];
+
+    Scalar x = pi[0].challengeParts[0];
+    Scalar f1 = pi[0].responseParts[0];
+
+    for (size_t i = 0; i < permutationCommits.size(); i++)
+    {
+        for (size_t j = 0; j < permutationCommits[i].size(); j++)
+        {
+            size_t piIndex = i * permutationCommits.size() + j + 1;
+
+            Twistpoint U1, U2, U3, U4, U5, U6, U7;
+            U2 = pi[piIndex].curvepointUniversals[0];
+            U3 = pi[piIndex].curvepointUniversals[1];
+            U5 = pi[piIndex].curvepointUniversals[2];
+
+            Scalar f2 = pi[piIndex].responseParts[0];
+            Scalar z1 = pi[piIndex].responseParts[1];
+            Scalar z2 = pi[piIndex].responseParts[2];
+
+            U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
+            
+            U4 = userTallyMasks[j] * (f1 * f2 * x) +
+                currPseudonyms[j] * (f1 * f2 * z2) +
+                h * (z2 * x * x) -
+                userTallyMaskCommits[i][j] * (x * x * x) -
+                U2 * (x * x) -
+                U3 * x;
+
+            U6 = userTallyMessages[j] * (f2 * x) +
+                nextGenerator * (f2 * z2) +
+                h * (z2 * x) -
+                userTallyMessageCommits[i][j] * (x * x) -
+                U5 * x;
+
+            U7 = g * z2 - userTallySeedCommits[i][j] * x;
+
+            oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
+        }
+    }
+
+    if (x != oracle(oracleInput.str()))
+    {
+        std::cerr << "User tallies not generated by permutation matrix." << std::endl;
+        return false;
+    }
+
+    for (size_t i = 0; i < userTallySeedCommits.size(); i++)
+    {
+        Twistpoint sum = userTallySeedCommits[i][0];
+
+        for (size_t j = 1; j < userTallySeedCommits[i].size(); j++)
+            sum = sum + userTallySeedCommits[i][j];
+
+        if (sum != Twistpoint())
+        {
+            std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
+            return false;
+        }
+    }
+
     return true;
 }
 

+ 14 - 5
prsona/src/localMain.cpp

@@ -369,6 +369,7 @@ int main(int argc, char *argv[])
     size_t numUsers = 5;
     size_t numRounds = 3;
     size_t numVotesPerRound = 3;
+    size_t lambda = 0;
     bool maliciousServers = true;
     bool maliciousClients = true;
     string seedStr = "seed";
@@ -383,23 +384,29 @@ int main(int argc, char *argv[])
     if (argc > 4)
         numVotesPerRound = atoi(argv[4]);
     if (argc > 5)
+        lambda = atoi(argv[5]);
+    if (argc > 6)
     {
-        bool setting = argv[5][0] == 't' || argv[5][0] == 'T';
+        bool setting = argv[6][0] == 't' || argv[6][0] == 'T';
         maliciousServers = setting;
     }
-    if (argc > 6)
+    if (argc > 7)
     {
-        bool setting = argv[6][0] == 't' || argv[6][0] == 'T';
+        bool setting = argv[7][0] == 't' || argv[7][0] == 'T';
         maliciousClients = setting;
     }
-    if (argc > 7)
-        seedStr = argv[7];
+    if (argc > 8)
+        seedStr = argv[8];
 
     cout << "Running the protocol with the following parameters: " << endl;
     cout << numServers << " PRSONA servers" << endl;
     cout << numUsers << " participants (voters/votees)" << endl;
     cout << numRounds << " epochs" << endl;
     cout << numVotesPerRound << " new (random) votes by each user per epoch" << endl;
+    cout << "Proof batching " << (lambda > 0 ? "IS" : "is NOT") << " in use." << (lambda > 0 ? " Batch parameter: " : "");
+    if (lambda > 0)
+        cout << lambda;
+    cout << endl;
     cout << "Servers are set to " << (maliciousServers ? "MALICIOUS" : "HBC") << " security" << endl;
     cout << "Clients are set to " << (maliciousClients ? "MALICIOUS" : "HBC") << " security" << endl;
     cout << "Current randomness seed: \"" << seedStr << "\"" << endl;
@@ -410,6 +417,8 @@ int main(int argc, char *argv[])
         PrsonaBase::set_server_malicious();
     if (maliciousClients)
         PrsonaBase::set_client_malicious();
+    if (lambda > 0)
+        PrsonaBase::set_lambda(lambda);
 
     // Entities we operate with
     PrsonaServerEntity servers(numServers);

+ 14 - 3
prsona/src/proof.cpp

@@ -6,7 +6,8 @@
 
 // Convert the bytes to a single integer, then make that a Scalar
 Scalar bytes_to_scalar(
-    const std::vector<uint8_t>& bytes)
+    const std::vector<uint8_t>& bytes,
+    size_t lambda)
 {
     std::stringstream stream;
     for (uint8_t b : bytes)
@@ -15,12 +16,22 @@ Scalar bytes_to_scalar(
     mpz_class value;
     value.set_str(stream.str(), 16);
 
+    if (lambda < 256)
+    {
+        mpz_class copy = value;
+        mpz_class modVal = 1;
+        modVal = modVal << lambda;
+
+        mpz_mod(value.get_mpz_t(), copy.get_mpz_t(), modVal.get_mpz_t());
+    }
+
     return Scalar(value);
 }
 
 // Random Oracle (i.e. SHA256)
 Scalar oracle(
-    const std::string& input)
+    const std::string& input,
+    size_t lambda)
 {
     uint32_t digest_length = SHA256_DIGEST_LENGTH;
     const EVP_MD* algorithm = EVP_sha256();
@@ -33,7 +44,7 @@ Scalar oracle(
     EVP_MD_CTX_destroy(context);
 
     std::vector<uint8_t> digestBytes(digest, digest + digest_length);
-    Scalar output = bytes_to_scalar(digestBytes);
+    Scalar output = bytes_to_scalar(digestBytes, lambda);
     OPENSSL_free(digest);
 
     return output;

+ 8 - 0
prsona/src/server.cpp

@@ -945,6 +945,14 @@ std::vector<std::vector<Proof>> PrsonaServer::epoch_calculations(
 {
     std::vector<std::vector<Scalar>> permutations = generate_permutation_matrix(power);
 
+    // for (size_t i = 0; i < permutations.size(); i++)
+    // {
+    //     std::cout << (i == 0 ? "[[" : " [");
+    //     for (size_t j = 0; j < permutations[i].size(); j++)
+    //         std::cout << std::hex << permutations[i][j] << std::dec << (j == permutations[i].size() - 1 ? "]" : " ");
+    //     std::cout << (i == permutations.size() - 1 ? "]" : "") << std::endl;
+    // }
+
     std::vector<std::vector<Proof>> retval, firstHalfTensorProof, secondHalfTensorProof;
     CurveBipoint curveG = bgnSystem.get_public_key().get_bipoint_curvegen();
     CurveBipoint curveH = bgnSystem.get_public_key().get_bipoint_curve_subgroup_gen();