From 4a2e4c3a5f8924800d495bc808fffc53c5e853a7 Mon Sep 17 00:00:00 2001 From: Aaron Feickert <66188213+AaronFeickert@users.noreply.github.com> Date: Thu, 3 Jun 2021 09:59:44 -0400 Subject: [PATCH] Sigma verifier batching --- src/sigma/sigma_primitives.h | 4 +- src/sigma/sigma_primitives.hpp | 29 +-- src/sigma/sigmaplus_prover.h | 6 +- src/sigma/sigmaplus_prover.hpp | 30 +-- src/sigma/sigmaplus_verifier.h | 11 +- src/sigma/sigmaplus_verifier.hpp | 401 +++++++++++++----------------- src/sigma/test/protocol_tests.cpp | 81 +++++- 7 files changed, 291 insertions(+), 271 deletions(-) diff --git a/src/sigma/sigma_primitives.h b/src/sigma/sigma_primitives.h index 7a338b0c4d..790806a97e 100644 --- a/src/sigma/sigma_primitives.h +++ b/src/sigma/sigma_primitives.h @@ -35,9 +35,9 @@ class SigmaPrimitives { static GroupElement commit(const GroupElement& g, const Exponent m, const GroupElement h, const Exponent r); - static void convert_to_sigma(uint64_t num, uint64_t n, uint64_t m, std::vector& out); + static void convert_to_sigma(std::size_t num, std::size_t n, std::size_t m, std::vector& out); - static std::vector convert_to_nal(uint64_t num, uint64_t n, uint64_t m); + static std::vector convert_to_nal(std::size_t num, std::size_t n, std::size_t m); static void generate_challenge(const std::vector& group_elements, Exponent& result_out); diff --git a/src/sigma/sigma_primitives.hpp b/src/sigma/sigma_primitives.hpp index 4666669764..ce3c8ee93a 100644 --- a/src/sigma/sigma_primitives.hpp +++ b/src/sigma/sigma_primitives.hpp @@ -23,18 +23,18 @@ GroupElement SigmaPrimitives::commit( template void SigmaPrimitives::convert_to_sigma( - uint64_t num, - uint64_t n, - uint64_t m, + std::size_t num, + std::size_t n, + std::size_t m, std::vector& out) { - uint64_t rem; - uint64_t j = 0; + std::size_t rem; + std::size_t j = 0; for (j = 0; j < m; ++j) { rem = num % n; num /= n; - for (uint64_t i = 0; i < n; ++i) { + for (std::size_t i = 0; i < n; ++i) { if(i == rem) out.push_back(Exponent(uint64_t(1))); else @@ -44,19 +44,16 @@ void SigmaPrimitives::convert_to_sigma( } template -std::vector SigmaPrimitives::convert_to_nal( - uint64_t num, - uint64_t n, - uint64_t m) { - std::vector result; - uint64_t rem; - uint64_t j = 0; +std::vector SigmaPrimitives::convert_to_nal( + std::size_t num, + std::size_t n, + std::size_t m) { + std::vector result; + result.reserve(m); while (num != 0) { - rem = num % n; + result.emplace_back(num % n); num /= n; - result.push_back(rem); - j++; } result.resize(m); return result; diff --git a/src/sigma/sigmaplus_prover.h b/src/sigma/sigmaplus_prover.h index 21e43d5926..e0de1e8b0e 100644 --- a/src/sigma/sigmaplus_prover.h +++ b/src/sigma/sigmaplus_prover.h @@ -13,7 +13,7 @@ class SigmaPlusProver{ public: SigmaPlusProver(const GroupElement& g, - const std::vector& h_gens, int n, int m); + const std::vector& h_gens, std::size_t n, std::size_t m); void proof(const std::vector& commits, std::size_t l, const Exponent& r, @@ -23,8 +23,8 @@ class SigmaPlusProver{ private: GroupElement g_; std::vector h_; - int n_; - int m_; + std::size_t n_; + std::size_t m_; }; } // namespace sigma diff --git a/src/sigma/sigmaplus_prover.hpp b/src/sigma/sigmaplus_prover.hpp index 741ce04e56..aa2837d542 100644 --- a/src/sigma/sigmaplus_prover.hpp +++ b/src/sigma/sigmaplus_prover.hpp @@ -5,8 +5,8 @@ template SigmaPlusProver::SigmaPlusProver( const GroupElement& g, const std::vector& h_gens, - int n, - int m) + std::size_t n, + std::size_t m) : g_(g) , h_(h_gens) , n_(n) @@ -33,7 +33,7 @@ void SigmaPlusProver::proof( // Values of Ro_k from Figure 5. std::vector Pk; Pk.resize(m_); - for (int k = 0; k < m_; ++k) { + for (std::size_t k = 0; k < m_; ++k) { Pk[k].randomize(); } R1ProofGenerator r1prover(g_, h_, sigma, rB, n_, m_); @@ -49,10 +49,10 @@ void SigmaPlusProver::proof( // last polynomial is special case if fPadding is true for (std::size_t i = 0; i < (fPadding ? N-1 : N); ++i) { std::vector& coefficients = P_i_k[i]; - std::vector I = SigmaPrimitives::convert_to_nal(i, n_, m_); + std::vector I = SigmaPrimitives::convert_to_nal(i, n_, m_); coefficients.push_back(a[I[0]]); coefficients.push_back(sigma[I[0]]); - for (int j = 1; j < m_; ++j) { + for (std::size_t j = 1; j < m_; ++j) { SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], coefficients); } } @@ -76,23 +76,23 @@ void SigmaPlusProver::proof( * \right] */ - std::vector I = SigmaPrimitives::convert_to_nal(N-1, n_, m_); - std::vector lj = SigmaPrimitives::convert_to_nal(l, n_, m_); + std::vector I = SigmaPrimitives::convert_to_nal(N-1, n_, m_); + std::vector lj = SigmaPrimitives::convert_to_nal(l, n_, m_); std::vector p_i_sum; p_i_sum.emplace_back(uint64_t(1)); std::vector> partial_p_s; // Pre-calculate product parts and calculate p_s(x) at the same time, put the latter into p_i_sum - for (int j = m_ - 1; j >= 0; j--) { + for (std::size_t j = m_; j > 0; j--) { partial_p_s.push_back(p_i_sum); - SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], p_i_sum); + SigmaPrimitives::new_factor(sigma[(j - 1) * n_ + I[j - 1]], a[(j - 1) * n_ + I[j - 1]], p_i_sum); } - for (int j = 0; j < m_; j++) { + for (std::size_t j = 0; j < m_; j++) { // \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) Exponent a_sum(uint64_t(0)); - for (int i = I[j] + 1; i < n_; i++) + for (std::size_t i = I[j] + 1; i < n_; i++) a_sum += a[j * n_ + i]; Exponent x_sum(uint64_t(lj[j] >= I[j]+1 ? 1 : 0)); @@ -101,7 +101,7 @@ void SigmaPlusProver::proof( SigmaPrimitives::new_factor(x_sum, a_sum, polynomial); // Multiply by x^j and add to the result - for (int k = 0; k < m_ - j; k++) + for (std::size_t k = 0; k < m_ - j; k++) p_i_sum[j + k] += polynomial[k]; } @@ -111,10 +111,10 @@ void SigmaPlusProver::proof( //computing G_k`s; std::vector Gk; Gk.reserve(m_); - for (int k = 0; k < m_; ++k) { + for (std::size_t k = 0; k < m_; ++k) { std::vector P_i; P_i.reserve(N); - for (size_t i = 0; i < N; ++i) { + for (std::size_t i = 0; i < N; ++i) { P_i.emplace_back(P_i_k[i][k]); } secp_primitives::MultiExponent mult(commits, P_i); @@ -138,7 +138,7 @@ void SigmaPlusProver::proof( z = r * x.exponent(uint64_t(m_)); Exponent sum; Exponent x_k(uint64_t(1)); - for (int k = 0; k < m_; ++k) { + for (std::size_t k = 0; k < m_; ++k) { sum += (Pk[k] * x_k); x_k *= x; } diff --git a/src/sigma/sigmaplus_verifier.h b/src/sigma/sigmaplus_verifier.h index 30902196c0..da6c7295b9 100644 --- a/src/sigma/sigmaplus_verifier.h +++ b/src/sigma/sigmaplus_verifier.h @@ -11,12 +11,17 @@ class SigmaPlusVerifier{ public: SigmaPlusVerifier(const GroupElement& g, const std::vector& h_gens, - int n, int m_); + std::size_t n, std::size_t m_); bool verify(const std::vector& commits, const SigmaPlusProof& proof, bool fPadding) const; + bool verify(const std::vector& commits, + const SigmaPlusProof& proof, + bool fPadding, + std::size_t setSize) const; + bool batch_verify(const std::vector& commits, const std::vector& serials, const vector& fPadding, @@ -43,8 +48,8 @@ class SigmaPlusVerifier{ private: GroupElement g_; std::vector h_; - int n; - int m; + std::size_t n; + std::size_t m; }; } // namespace sigma diff --git a/src/sigma/sigmaplus_verifier.hpp b/src/sigma/sigmaplus_verifier.hpp index e97771dd5c..39995ac01b 100644 --- a/src/sigma/sigmaplus_verifier.hpp +++ b/src/sigma/sigmaplus_verifier.hpp @@ -1,13 +1,13 @@ - #include -namespace sigma{ + +namespace sigma { template SigmaPlusVerifier::SigmaPlusVerifier( const GroupElement& g, const std::vector& h_gens, - int n, - int m) + std::size_t n, + std::size_t m) : g_(g) , h_(h_gens) , n(n) @@ -19,258 +19,232 @@ bool SigmaPlusVerifier::verify( const std::vector& commits, const SigmaPlusProof& proof, bool fPadding) const { + // Prepare a batch with a single proof + std::vector serials = { Exponent(uint64_t(0)) }; + std::vector fPadding_ = { fPadding }; + std::vector setSizes = { commits.size() }; + std::vector> proofs = { proof }; + + return batch_verify( + commits, serials, fPadding_, setSizes, proofs + ); +} + +template +bool SigmaPlusVerifier::verify( + const std::vector& commits, + const SigmaPlusProof& proof, + bool fPadding, + std::size_t setSize) const { + // Prepare a batch with a single proof + std::vector serials = { Exponent(uint64_t(0)) }; + std::vector fPadding_ = { fPadding }; + std::vector setSizes = { setSize }; + std::vector> proofs = { proof }; + + return batch_verify( + commits, serials, fPadding_, setSizes, proofs + ); +} - R1ProofVerifier r1ProofVerifier(g_, h_, proof.B_, n, m); - std::vector f; - const R1Proof& r1Proof = proof.r1Proof_; - if (!r1ProofVerifier.verify(r1Proof, f, true /* Skip verification of final response */)) { - LogPrintf("Sigma spend failed due to r1 proof incorrect."); +// Verify a batch of one-of-many proofs +template +bool SigmaPlusVerifier::batch_verify( + const std::vector& commits, + const std::vector& serials, + const std::vector& fPadding, + const std::vector& setSizes, + const std::vector>& proofs) const { + // Sanity checks + if (n < 2 || m < 2) { + LogPrintf("Verifier parameters are invalid"); return false; } + std::size_t M = proofs.size(); + std::size_t N = (std::size_t)pow(n,m); - if (!proof.B_.isMember() || proof.B_.isInfinity()) { - LogPrintf("Sigma spend failed due to value of B outside of group."); + if (commits.size() == 0) { + LogPrintf("Cannot have empty commitment set"); return false; } - - const std::vector & Gk = proof.Gk_; - for (int k = 0; k < m; ++k) { - if (!Gk[k].isMember() || Gk[k].isInfinity()) { - LogPrintf("Sigma spend failed due to value of GK[i] outside of group."); - return false; - } + if (commits.size() > N) { + LogPrintf("Commitment set is too large"); + return false; } - - // Compute value of challenge X, then continue R1 proof and sigma final response proof. - std::vector group_elements = { - r1Proof.A_, proof.B_, r1Proof.C_, r1Proof.D_}; - - group_elements.insert(group_elements.end(), Gk.begin(), Gk.end()); - Exponent challenge_x; - SigmaPrimitives::generate_challenge(group_elements, challenge_x); - - // Now verify the final response of r1 proof. Values of "f" are finalized only after this call. - if (!r1ProofVerifier.verify_final_response(r1Proof, challenge_x, f)) { - LogPrintf("Sigma spend failed due to incorrect final response."); + if (h_.size() != n * m) { + LogPrintf("Generator vector size is invalid"); return false; } - - if(!proof.z_.isMember() || proof.z_.isZero()) { - LogPrintf("Sigma spend failed due to value of Z outside of group."); + if (serials.size() != M) { + LogPrintf("Invalid number of serials provided"); return false; } - - if (commits.empty()) { - LogPrintf("No mints in the anonymity set"); + if (fPadding.size() != M) { + LogPrintf("Padding vector size is invalid"); return false; } - - std::size_t N = commits.size(); - std::vector f_i_; - f_i_.resize(N); - - compute_fis(m, f, f_i_); - - if (fPadding) { - /* - * Optimization for getting power for last 'commits' array element is done similarly to the one used in creating - * a proof. The fact that sum of any row in 'f' array is 'x' (challenge value) is used. - * - * Math (in TeX notation): - * - * \sum_{i=s+1}^{N-1} \prod_{j=0}^{m-1}f_{j,i_j} = - * \sum_{j=0}^{m-1} - * \left[ - * \left( \sum_{i=s_j+1}^{n-1}f_{j,i} \right) - * \left( \prod_{k=j}^{m-1}f_{k,s_k} \right) - * x^j - * \right] - */ - - Exponent pow(uint64_t(1)); - std::vector I = SigmaPrimitives::convert_to_nal(N - 1, n, m); - vector f_part_product; // partial product of f array elements for lastIndex - for (int j = m - 1; j >= 0; j--) { - f_part_product.push_back(pow); - pow *= f[j * n + I[j]]; - } - - Exponent xj(uint64_t(1));; // x^j - for (int j = 0; j < m; j++) { - Exponent fi_sum(uint64_t(0)); - for (int i = I[j] + 1; i < n; i++) - fi_sum += f[j*n + i]; - pow += fi_sum * xj * f_part_product[m - j - 1]; - xj *= challenge_x; + + // All proof elements must be valid + for (std::size_t t = 0; t < M; ++t) { + if (!membership_checks(proofs[t])) { + LogPrintf("Sigma verification failed due to membership check failed."); + return false; } - f_i_[N - 1] = pow; } - secp_primitives::MultiExponent mult(commits, f_i_); - GroupElement t1 = mult.get_multiple(); - - GroupElement t2; - Exponent x_k(uint64_t(1)); - for(int k = 0; k < m; ++k){ - t2 += (Gk[k] * (x_k.negate())); - x_k *= challenge_x; + // Final batch multiscalar multiplication + Scalar g_scalar = Scalar(uint64_t(0)); // associated to g_ + Scalar h_scalar = Scalar(uint64_t(0)); // associated to h_ + std::vector h_scalars; // associated to (h_) + std::vector commit_scalars; // associated to commitment list + h_scalars.reserve(n * m); + h_scalars.resize(n * m); + for (size_t i = 0; i < n * m; i++) { + h_scalars[i] = Scalar(uint64_t(0)); } - - GroupElement left(t1 + t2); - if (left != SigmaPrimitives::commit(g_, Exponent(uint64_t(0)), h_[0], proof.z_)) { - LogPrintf("Sigma spend failed due to final proof verification failure."); - return false; + commit_scalars.reserve(commits.size()); + commit_scalars.resize(commits.size()); + for (size_t i = 0; i < commits.size(); i++) { + commit_scalars[i] = Scalar(uint64_t(0)); } - return true; -} - -template -bool SigmaPlusVerifier::batch_verify( - const std::vector& commits, - const std::vector& serials, - const vector& fPadding, - const std::vector& setSizes, - const vector>& proofs) const { - - int M = proofs.size(); - int N = commits.size(); - - if (commits.empty()) - return false; - - for(int t = 0; t < M; ++t) { - if (!membership_checks(proofs[t])) { - LogPrintf("Sigma spend failed due to membership check failed."); - return false; - } + // Set up the final batch elements + std::vector points; + std::vector scalars; + std::size_t final_size = 2 + m * n + commits.size(); // g, h, (h_), (commits) + for (std::size_t t = 0; t < M; t++) { + final_size += 4 + proofs[t].Gk_.size(); // A, B, C, D, (G) } - std::vector challenges; - challenges.resize(M); + points.reserve(final_size); + scalars.reserve(final_size); - std::vector> f_; - f_.resize(M); - for (int t = 0; t < M; ++t) - { - std::vector group_elements = { - proofs[t].r1Proof_.A_, proofs[t].B_, proofs[t].r1Proof_.C_, proofs[t].r1Proof_.D_}; - - group_elements.insert(group_elements.end(), proofs[t].Gk_.begin(), proofs[t].Gk_.end()); - SigmaPrimitives::generate_challenge(group_elements, challenges[t]); + // Index decomposition, which is common among all proofs + std::vector> I_; + I_.reserve(N); + I_.resize(N); + for (std::size_t i = 0; i < commits.size(); i++) { + I_[i] = SigmaPrimitives::convert_to_nal(i, n, m); + } - if(!compute_fs(proofs[t], challenges[t], f_[t]) || !abcd_checks(proofs[t], challenges[t], f_[t])) { - LogPrintf("Sigma spend failed due to compute_fs or abcd_checks failed."); + // Process all proofs + for (std::size_t t = 0; t < M; t++) { + SigmaPlusProof proof = proofs[t]; + + // Compute the challenge + Exponent x; + std::vector challenge_elements = { + proof.r1Proof_.A_, + proof.B_, + proof.r1Proof_.C_, + proof.r1Proof_.D_, + }; + challenge_elements.insert(challenge_elements.end(), proof.Gk_.begin(), proof.Gk_.end()); + SigmaPrimitives::generate_challenge(challenge_elements, x); + + // Generate random verifier weights + Scalar w1, w2, w3; + w1.randomize(); + w2.randomize(); + w3.randomize(); + + // Reconstruct f-matrix + std::vector f_; + if (!compute_fs(proof, x, f_)) { + LogPrintf("Invalid matrix reconstruction"); return false; } - } - std::vector y; - y.resize(M); - for (int t = 0; t < M; ++t) - y[t].randomize(); + // A, B, C, D (and associated commitments) + points.emplace_back(proof.r1Proof_.A_); + scalars.emplace_back(w1.negate()); + points.emplace_back(proof.B_); + scalars.emplace_back(x.negate() * w1); + points.emplace_back(proof.r1Proof_.C_); + scalars.emplace_back(x.negate() * w2); + points.emplace_back(proof.r1Proof_.D_); + scalars.emplace_back(w2.negate()); + + g_scalar += proof.r1Proof_.ZA_ * w1 + proof.r1Proof_.ZC_ * w2; + for (std::size_t i = 0; i < m * n; i++) { + h_scalars[i] += f_[i] * (w1 + (x - f_[i]) * w2); + } - std::vector f_i_t; - f_i_t.resize(N); - GroupElement right; - Scalar exp; + // Input sets + h_scalar += proof.z_ * w3.negate(); - std::vector > I_; - I_.resize(N); - for (int i = 0; i < N ; ++i) - I_[i] = SigmaPrimitives::convert_to_nal(i, n, m); - - for (int t = 0; t < M; ++t) - { - right += (SigmaPrimitives::commit(g_, Scalar(uint64_t(0)), h_[0], proofs[t].z_)) * y[t]; + Scalar f_i(uint64_t(1)); Scalar e; size_t size = setSizes[t]; - size_t start = N - size; + size_t start = commits.size() - size; - Scalar f_i(uint64_t(1)); - vector::iterator ptr = f_i_t.begin() + start; - compute_batch_fis(f_i, m, f_[t], y[t], e, ptr, ptr, ptr + size - 1); + vector::iterator ptr = commit_scalars.begin() + start; + compute_batch_fis(f_i, m, f_, w3, e, ptr, ptr, ptr + size - 1); if(fPadding[t]) { - /* - * Optimization for getting power for last 'commits' array element is done similarly to the one used in creating - * a proof. The fact that sum of any row in 'f' array is 'x' (challenge value) is used. - * - * Math (in TeX notation): - * - * \sum_{i=s+1}^{N-1} \prod_{j=0}^{m-1}f_{j,i_j} = - * \sum_{j=0}^{m-1} - * \left[ - * \left( \sum_{i=s_j+1}^{n-1}f_{j,i} \right) - * \left( \prod_{k=j}^{m-1}f_{k,s_k} \right) - * x^j - * \right] - */ - Scalar pow(uint64_t(1)); - vector f_part_product; // partial product of f array elements for lastIndex - for (int j = m - 1; j >= 0; j--) { + vector f_part_product; + for (std::size_t j = m; j > 0; j--) { f_part_product.push_back(pow); - pow *= f_[t][j * n + I_[size - 1][j]]; + pow *= f_[(j - 1) * n + I_[size - 1][j - 1]]; } - NthPower xj(challenges[t]); + NthPower xj(x); for (std::size_t j = 0; j < m; j++) { Scalar fi_sum(uint64_t(0)); for (std::size_t i = I_[size - 1][j] + 1; i < n; i++) - fi_sum += f_[t][j * n + i]; + fi_sum += f_[j*n + i]; pow += fi_sum * xj.pow * f_part_product[m - j - 1]; xj.go_next(); } - f_i_t[N - 1] += pow * y[t]; + commit_scalars[commits.size() - 1] += pow * w3; e += pow; } else { f_i = (uint64_t(1)); for (std::size_t j = 0; j < m; ++j) { - f_i *= f_[t][j*n + I_[size - 1][j]]; + f_i *= f_[j*n + I_[size - 1][j]]; } - f_i_t[N - 1] += f_i * y[t]; + commit_scalars[commits.size() - 1] += f_i * w3; e += f_i; } - e *= serials[t] * y[t]; - exp += e; - } + e *= serials[t] * w3.negate(); + g_scalar += e; - secp_primitives::MultiExponent mult(commits, f_i_t); - GroupElement t1 = mult.get_multiple(); - - std::vector> x_t_k_neg; - x_t_k_neg.resize(M); - for (int t = 0; t < M; ++t) { - x_t_k_neg[t].reserve(m); - NthPower x_k(challenges[t]); - for (uint64_t k = 0; k < m; ++k) { - x_t_k_neg[t].emplace_back(x_k.pow.negate()); + NthPower x_k(x); + for (std::size_t k = 0; k < m; k++) { + points.emplace_back(proof.Gk_[k]); + scalars.emplace_back(x_k.pow.negate() * w3); x_k.go_next(); } } - GroupElement t2; - for (int t = 0; t < M; ++t) { - const std::vector & Gk = proofs[t].Gk_; - GroupElement term; - for (std::size_t k = 0; k < m; ++k) - { - term += ((Gk[k]) * x_t_k_neg[t][k]); - } - term *= y[t]; - t2 += term; + // Add common generators + points.emplace_back(g_); + scalars.emplace_back(g_scalar); + points.emplace_back(h_[0]); + scalars.emplace_back(h_scalar); + for (std::size_t i = 0; i < m * n; i++) { + points.emplace_back(h_[i]); + scalars.emplace_back(h_scalars[i]); + } + for (std::size_t i = 0; i < commits.size(); i++) { + points.emplace_back(commits[i]); + scalars.emplace_back(commit_scalars[i]); } - GroupElement left(t1 + t2); - right += g_ * exp; - if(left != right) + // Verify the batch + if(points.size() != scalars.size() || points.size() != final_size) { + LogPrintf("Unexpected final evaluation size"); return false; - - return true; + } + secp_primitives::MultiExponent result(points, scalars); + if (result.get_multiple().isInfinity()) { + return true; + } + return false; } template @@ -311,8 +285,8 @@ bool SigmaPlusVerifier::compute_fs( const SigmaPlusProof& proof, const Exponent& x, std::vector& f_) const { - for(unsigned int j = 0; j < proof.r1Proof_.f_.size(); ++j) { - if(proof.r1Proof_.f_[j] == x) + for (std::size_t j = 0; j < proof.r1Proof_.f_.size(); ++j) { + if (proof.r1Proof_.f_[j] == x) return false; } @@ -321,8 +295,8 @@ bool SigmaPlusVerifier::compute_fs( { f_.push_back(Scalar(uint64_t(0))); Scalar temp; - int k = n - 1; - for (int i = 0; i < k; ++i) + std::size_t k = n - 1; + for (std::size_t i = 0; i < k; ++i) { temp += proof.r1Proof_.f_[j * k + i]; f_.emplace_back(proof.r1Proof_.f_[j * k + i]); @@ -332,27 +306,6 @@ bool SigmaPlusVerifier::compute_fs( return true; } -template -bool SigmaPlusVerifier::abcd_checks( - const SigmaPlusProof& proof, - const Exponent& x, - const std::vector& f_) const { - Exponent c; - c.randomize(); - - // Aggregating two checks into one, B^x * A = Comm(..) and C^x * D = Comm(..) - std::vector f_plus_f_prime; - f_plus_f_prime.reserve(f_.size()); - for(std::size_t i = 0; i < f_.size(); i++) - f_plus_f_prime.emplace_back(f_[i] * c + f_[i] * (x - f_[i])); - - GroupElement right; - SigmaPrimitives::commit(g_, h_, f_plus_f_prime, proof.r1Proof_.ZA_ * c + proof.r1Proof_.ZC_, right); - if(((proof.B_ * x + proof.r1Proof_.A_) * c + proof.r1Proof_.C_ * x + proof.r1Proof_.D_) != right) - return false; - return true; -} - template void SigmaPlusVerifier::compute_fis(int j, const std::vector& f, std::vector& f_i_) const { Exponent f_i(uint64_t(1)); @@ -365,14 +318,14 @@ void SigmaPlusVerifier::compute_fis(const Exponent& f_i, j--; if (j == -1) { - if(ptr < end_ptr) + if (ptr < end_ptr) *ptr++ += f_i; return; } Scalar t; - for (int i = 0; i < n; i++) + for (std::size_t i = 0; i < n; i++) { t = f[j * n + i]; t *= f_i; @@ -394,7 +347,7 @@ void SigmaPlusVerifier::compute_batch_fis( j--; if (j == -1) { - if(ptr >= start_ptr && ptr < end_ptr){ + if (ptr >= start_ptr && ptr < end_ptr){ *ptr++ += f_i * y; e += f_i; } @@ -403,7 +356,7 @@ void SigmaPlusVerifier::compute_batch_fis( Exponent t; - for (int i = 0; i < n; i++) + for (std::size_t i = 0; i < n; i++) { t = f[j * n + i]; t *= f_i; diff --git a/src/sigma/test/protocol_tests.cpp b/src/sigma/test/protocol_tests.cpp index 4e23a1ea91..5c8acd3c69 100644 --- a/src/sigma/test/protocol_tests.cpp +++ b/src/sigma/test/protocol_tests.cpp @@ -11,16 +11,16 @@ BOOST_FIXTURE_TEST_SUITE(sigma_protocol_tests, ZerocoinTestingSetup200) BOOST_AUTO_TEST_CASE(one_out_of_n) { auto params = sigma::Params::get_default(); - int N = 16384; - int n = params->get_n(); - int m = params->get_m(); - int index = 0; + std::size_t N = 16384; + std::size_t n = params->get_n(); + std::size_t m = params->get_m(); + std::size_t index = 0; secp_primitives::GroupElement g; g.randomize(); std::vector h_gens; h_gens.resize(n * m); - for(int i = 0; i < n * m; ++i ){ + for (std::size_t i = 0; i < n * m; ++i ){ h_gens[i].randomize(); } secp_primitives::Scalar r; @@ -28,15 +28,15 @@ BOOST_AUTO_TEST_CASE(one_out_of_n) sigma::SigmaPlusProver prover(g,h_gens, n, m); std::vector commits; - for(int i = 0; i < N; ++i){ - if(i == index){ + for (std::size_t i = 0; i < N; ++i) { + if (i == index) { secp_primitives::GroupElement c; secp_primitives::Scalar zero(uint64_t(0)); c = sigma::SigmaPrimitives::commit(g, zero, h_gens[0], r); commits.push_back(c); } - else{ + else { commits.push_back(secp_primitives::GroupElement()); commits[i].randomize(); } @@ -50,6 +50,71 @@ BOOST_AUTO_TEST_CASE(one_out_of_n) BOOST_CHECK(verifier.verify(commits, proof, true)); } +BOOST_AUTO_TEST_CASE(one_out_of_n_batch) +{ + auto params = sigma::Params::get_default(); + const secp_primitives::Scalar zero(uint64_t(0)); + const std::size_t N = 16000; // n^m == 16384 + const std::size_t n = params->get_n(); + const std::size_t m = params->get_m(); + const std::vector index = { 0, 1, 2, N - 1 }; + const std::vector set_sizes = { N, N - 1, N - 1, 16 }; + const std::vector serials = { zero, zero, zero, zero }; + const std::vector fPadding = { true, true, true, true }; + + // Generators + secp_primitives::GroupElement g; + g.randomize(); + std::vector h_gens; + h_gens.resize(n * m); + for (std::size_t i = 0; i < n * m; ++i ){ + h_gens[i].randomize(); + } + sigma::SigmaPlusProver prover(g, h_gens, n, m); + + std::vector commits; + + // All commitments + for (std::size_t i = 0; i < N; ++i) { + commits.push_back(secp_primitives::GroupElement()); + commits[i].randomize(); + } + + // Known commitments + std::vector r; + r.resize(index.size()); + for (std::size_t i = 0; i < index.size(); i++) { + r[i].randomize(); + commits[index[i]] = h_gens[0] * r[i]; + } + + // Build the proofs + std::vector> proofs; + proofs.reserve(index.size()); + sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); + for (std::size_t i = 0; i < index.size(); i++) { + sigma::SigmaPlusProof proof(n, m); + std::vector commits_(commits.begin() + N - set_sizes[i], commits.end()); + + // Check commitment validity and prove + BOOST_CHECK(h_gens[0] * r[i] == commits[index[i]]); + BOOST_CHECK(h_gens[0] * r[i] == commits_[index[i] - (N - set_sizes[i])]); + prover.proof(commits_, index[i] - (N - set_sizes[i]), r[i], true, proof); + proofs.emplace_back(proof); + + // Test individual verification + BOOST_CHECK(verifier.verify(commits_, proof, true)); + BOOST_CHECK(verifier.verify(commits, proof, true, set_sizes[i])); + } + + // Test batch verification + BOOST_CHECK(verifier.batch_verify(commits, serials, fPadding, set_sizes, proofs)); + + // Invalidate the batch + proofs[0] = proofs[1]; + BOOST_CHECK(!verifier.batch_verify(commits, serials, fPadding, set_sizes, proofs)); +} + BOOST_AUTO_TEST_CASE(one_out_of_n_padding) { auto params = sigma::Params::get_default();