Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
269231b
shplemini works, gemini tests need to be re-designed
iakovenkos Mar 10, 2025
75d411c
interleaving fails
iakovenkos Mar 10, 2025
f1c9981
interleaving fixed
iakovenkos Mar 10, 2025
666c323
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 11, 2025
9b7af30
gemini tests
iakovenkos Mar 11, 2025
12eca3f
recursion fixed
iakovenkos Mar 11, 2025
07a605f
more consistency
iakovenkos Mar 12, 2025
32b3dda
cleanup
iakovenkos Mar 12, 2025
639fef2
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 12, 2025
5105319
fix client ivc
iakovenkos Mar 12, 2025
ce37576
Merge branch 'si/fix-gemini' of github.com:AztecProtocol/aztec-packag…
iakovenkos Mar 12, 2025
0acc32d
docs + constants
iakovenkos Mar 13, 2025
f9a0d92
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 13, 2025
b976e27
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 14, 2025
73d2b18
computation of a_0_pos returns array of all pos evals
iakovenkos Mar 14, 2025
9284bfd
computeInvertedGeminiDenominators modified
iakovenkos Mar 14, 2025
b9beafb
modified the batching loop
iakovenkos Mar 14, 2025
14380d8
stack too deep resolved
iakovenkos Mar 14, 2025
80adaba
debugging
iakovenkos Mar 14, 2025
5227759
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 14, 2025
9eccb43
basic sol tests fixed
iakovenkos Mar 14, 2025
cd11f0c
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 17, 2025
cc99398
porting changes
iakovenkos Mar 17, 2025
1a1a938
fix character
iakovenkos Mar 17, 2025
181d907
logN-> LOG_N
iakovenkos Mar 17, 2025
34452ce
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 17, 2025
059fa93
update shplonkNuChallengeElements
iakovenkos Mar 17, 2025
e90de46
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 17, 2025
b01d919
undo last modifications
iakovenkos Mar 17, 2025
f871627
fix tests
iakovenkos Mar 17, 2025
147c36d
docs
iakovenkos Mar 17, 2025
db10c67
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 17, 2025
d8e1fde
fix missing counter update
iakovenkos Mar 17, 2025
9456297
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 17, 2025
62a02b6
docs improvements + minor simplification after review
iakovenkos Mar 18, 2025
e8b34f8
Merge branch 'si/fix-gemini' of github.com:AztecProtocol/aztec-packag…
iakovenkos Mar 18, 2025
49e9de9
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 18, 2025
e96f921
Merge branch 'master' into si/fix-gemini
iakovenkos Mar 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ template <typename Curve> class ProverOpeningClaim {
public:
Polynomial polynomial; // p
OpeningPair<Curve> opening_pair; // (challenge r, evaluation v = p(r))
// Gemini Folds have to be opened at `challenge` and -`challenge`. Instead of copying a polynomial into 2 claims, we
// raise the flag that turns on relevant claim processing logic in Shplonk.
bool gemini_fold = false;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
* - A₀₊(X) = F(X) + G(X)/r
* - A₀₋(X) = F(X) − G(X)/r
* So that A₀₊(r) = A₀(r) and A₀₋(-r) = A₀(-r).
* The verifier is able to computed the simulated commitments to A₀₊(X) and A₀₋(X)
* The verifier is able to compute the simulated commitments to A₀₊(X) and A₀₋(X)
* since they are linear-combinations of the commitments [fⱼ] and [gⱼ].
*/
namespace bb {

/**
* @brief Prover output (evalutation pair, witness) that can be passed on to Shplonk batch opening.
* @details Evaluation pairs {r, A₀₊(r)}, {-r, A₀₋(-r)}, {-r^{2^j}, Aⱼ(-r^{2^j)}, j = [1, ..., m-1]
* and witness (Fold) polynomials
* @details Evaluation pairs {r, A₀₊(r)}, {-r, A₀₋(-r)}, {r^{2^j}, Aⱼ(r^{2^j)}, {-r^{2^j}, Aⱼ(-r^{2^j)}, j = [1, ...,
* m-1] and witness (Fold) polynomials
* [
* A₀₊(X) = F(X) + r⁻¹⋅G(X)
* A₀₋(X) = F(X) - r⁻¹⋅G(X)
Expand Down Expand Up @@ -443,18 +443,23 @@ template <typename Curve> class GeminiVerifier_ {
p_neg = transcript->template receive_from_prover<Fr>("Gemini:P_0_neg");
}

// Compute the full of evaluation A₀(r) = A₀₊(r) + P₊(r^s)
Fr full_a_0_pos = compute_gemini_batched_univariate_evaluation(
// Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1
std::vector<Fr> gemini_fold_pos_evaluations = compute_fold_pos_evaluations(
num_variables, batched_evaluation, multilinear_challenge, r_squares, evaluations, p_neg);
// Extract the evaluation A₀(r) = A₀₊(r) + P₊(r^s)
auto full_a_0_pos = gemini_fold_pos_evaluations[0];
std::vector<OpeningClaim<Curve>> fold_polynomial_opening_claims;
fold_polynomial_opening_claims.reserve(num_variables + 1);
fold_polynomial_opening_claims.reserve(2 * num_variables + 2);

// ( [A₀₊], r, A₀₊(r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { r, full_a_0_pos - p_pos }, C0_r_pos });
// ( [A₀₋], -r, A₀-(-r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { -r, evaluations[0] }, C0_r_neg });
for (size_t l = 0; l < num_variables - 1; ++l) {
// ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) )
// ([Aₗ], r^{2ˡ}, Aₗ(r^{2ˡ}) )
fold_polynomial_opening_claims.emplace_back(
OpeningClaim<Curve>{ { r_squares[l + 1], gemini_fold_pos_evaluations[l + 1] }, commitments[l] });
// ([Aₗ], −r^{2ˡ}, Aₗ(−r^{2ˡ}) )
fold_polynomial_opening_claims.emplace_back(
OpeningClaim<Curve>{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] });
}
Expand Down Expand Up @@ -493,36 +498,49 @@ template <typename Curve> class GeminiVerifier_ {
}

/**
* @brief Compute the expected evaluation of the univariate commitment to the batched polynomial.
* @brief Compute \f$ A_0(r), A_1(r^2), \ldots, A_{d-1}(r^{2^{d-1}})\f$
*
* Compute the evaluation \f$ A_0(r) = \sum \rho^i \cdot f_i + \frac{1}{r} \cdot \sum \rho^{i+k} g_i \f$, where \f$
* Recall that \f$ A_0(r) = \sum \rho^i \cdot f_i + \frac{1}{r} \cdot \sum \rho^{i+k} g_i \f$, where \f$
* k \f$ is the number of "unshifted" commitments.
*
* @details Initialize \f$ A_{d}(r) \f$ with the batched evaluation \f$ \sum \rho^i f_i(\vec{u}) + \sum \rho^{i+k}
* g_i(\vec{u}) \f$. The folding property ensures that
* \f{align}{
* A_\ell\left(r^{2^\ell}\right) = (1 - u_{\ell-1}) \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) +
* A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2}
* + u_{\ell-1} \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) -
* A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2r^{2^{\ell-1}}}
* \f}
* Therefore, the verifier can recover \f$ A_0(r) \f$ by solving several linear equations.
* @details Initialize `a_pos` = \f$ A_{d}(r) \f$ with the batched evaluation \f$ \sum \rho^i f_i(\vec{u}) + \sum
* \rho^{i+k} g_i(\vec{u}) \f$. The verifier recovers \f$ A_{l-1}(r^{2^{l-1}}) \f$ from the "negative" value \f$
* A_{l-1}\left(-r^{2^{l-1}}\right) \f$ received from the prover and the value \f$ A_{l}\left(r^{2^{l}}\right) \f$
* computed at the previous step. Namely, the verifier computes
* \f{align}{ A_{l-1}\left(r^{2^{l-1}}\right) =
* \frac{2 \cdot r^{2^{l-1}} \cdot A_{l}\left(r^{2^l}\right) - A_{l-1}\left( -r^{2^{l-1}} \right)\cdot
* \left(r^{2^{l-1}} (1-u_{l-1}) - u_{l-1}\right)} {r^{2^{l-1}} (1- u_{l-1}) + u_{l-1}}. \f}
*
* In the case of interleaving, the first "negative" evaluation has to be corrected by the contribution from \f$
* P_{-}(-r^s)\f$, where \f$ s \f$ is the size of the group to be interleaved.
*
* @param batched_mle_eval The evaluation of the batched polynomial at \f$ (u_0, \ldots, u_{d-1})\f$.
* @param evaluation_point Evaluation point \f$ (u_0, \ldots, u_{d-1}) \f$.
* @param challenge_powers Powers of \f$ r \f$, \f$ r^2 \), ..., \( r^{2^{m-1}} \f$.
* @param fold_polynomial_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$.
* @param batched_evaluation The evaluation of the batched polynomial at \f$ (u_0, \ldots, u_{d-1})\f$.
* @param evaluation_point Evaluation point \f$ (u_0, \ldots, u_{d-1}) \f$ padded to CONST_PROOF_SIZE_LOG_N.
* @param challenge_powers Powers of \f$ r \f$, \f$ r^2 \), ..., \( r^{2^{d-1}} \f$.
* @param fold_neg_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$.
* @return Evaluation \f$ A_0(r) \f$.
*/
static Fr compute_gemini_batched_univariate_evaluation(
static std::vector<Fr> compute_fold_pos_evaluations(
const size_t num_variables,
Fr& batched_eval_accumulator,
const Fr& batched_evaluation,
std::span<const Fr> evaluation_point, // CONST_PROOF_SIZE
std::span<const Fr> challenge_powers, // r_squares CONST_PROOF_SIZE_LOG_N
std::span<const Fr> fold_polynomial_evals,
std::span<const Fr> fold_neg_evals,
Fr p_neg = Fr(0))
{
std::vector<Fr> evals(fold_polynomial_evals.begin(), fold_polynomial_evals.end());
std::vector<Fr> evals(fold_neg_evals.begin(), fold_neg_evals.end());

Fr eval_pos_prev = batched_evaluation;

Fr zero{ 0 };
if constexpr (Curve::is_stdlib_type) {
zero.convert_constant_to_fixed_witness(fold_neg_evals[0].get_context());
}

std::vector<Fr> fold_pos_evaluations;
fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N);
// Either a computed eval of A_i at r^{2^i}, or 0
Fr value_to_emplace;

// Add the contribution of P-((-r)ˢ) to get A_0(-r), which is 0 if there are no interleaved polynomials
evals[0] += p_neg;
Expand All @@ -536,26 +554,33 @@ template <typename Curve> class GeminiVerifier_ {
const Fr& eval_neg = evals[l - 1];
// Get A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾)
// Compute the numerator
Fr batched_eval_round_acc =
((challenge_power * batched_eval_accumulator * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u));
Fr eval_pos = ((challenge_power * eval_pos_prev * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u));
// Divide by the denominator
batched_eval_round_acc *= (challenge_power * (Fr(1) - u) + u).invert();
eval_pos *= (challenge_power * (Fr(1) - u) + u).invert();

if constexpr (Curve::is_stdlib_type) {
auto builder = evaluation_point[0].get_context();
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation!
stdlib::bool_t dummy_round = stdlib::witness_t(builder, l > num_variables);
batched_eval_accumulator =
Fr::conditional_assign(dummy_round, batched_eval_accumulator, batched_eval_round_acc);
// If current index is bigger than log_circuit_size, we propagate `batched_evaluation` to the next
// round. Otherwise, current `eval_pos` A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) becomes `eval_pos_prev` in the round l-2.
eval_pos_prev = Fr::conditional_assign(dummy_round, eval_pos_prev, eval_pos);
// If current index is bigger than log_circuit_size, we emplace 0, which is later multiplied against
// Commitment::one().
value_to_emplace = Fr::conditional_assign(dummy_round, zero, eval_pos_prev);

} else {
if (l <= num_variables) {
batched_eval_accumulator = batched_eval_round_acc;
}
}
// Perform the same logic natively
bool dummy_round = l > num_variables;
eval_pos_prev = dummy_round ? eval_pos_prev : eval_pos;
value_to_emplace = dummy_round ? zero : eval_pos_prev;
};
fold_pos_evaluations.emplace_back(value_to_emplace);
}

return batched_eval_accumulator;
std::reverse(fold_pos_evaluations.begin(), fold_pos_evaluations.end());

return fold_pos_evaluations;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,46 @@ template <class Curve> class GeminiTest : public CommitmentTest<Curve> {
auto prover_output = GeminiProver::prove(
this->n, mock_claims.polynomial_batcher, multilinear_evaluation_point, ck, prover_transcript);

// The prover output needs to be completed by adding the "positive" Fold claims, i.e. evaluations of Fold^(i) at
// r^{2^i} for i=1, ..., d-1. Although here we are copying polynomials, it is not the case when GeminiProver is
// combined with ShplonkProver.
std::vector<ProverOpeningClaim<Curve>> prover_claims_with_pos_evals;
// `prover_output` consists of d+1 opening claims, we add another d-1 claims for each positive evaluation
// Fold^i(r^{2^i}) for i = 1, ..., d-1
const size_t total_num_claims = 2 * log_n;
prover_claims_with_pos_evals.reserve(total_num_claims);

for (auto& claim : prover_output) {
if (claim.gemini_fold) {
if (claim.gemini_fold) {
// "positive" evaluation challenge r^{2^i} for i = 1, ..., d-1
const Fr evaluation_challenge = -claim.opening_pair.challenge;
// Fold^(i) at r^{2^i} for i=1, ..., d-1
const Fr pos_evaluation = claim.polynomial.evaluate(evaluation_challenge);
// Add the positive Fold claims to the vector of claims
ProverOpeningClaim<Curve> pos_fold_claim = { .polynomial = claim.polynomial,
.opening_pair = { .challenge = evaluation_challenge,
.evaluation = pos_evaluation } };
prover_claims_with_pos_evals.emplace_back(pos_fold_claim);
}
}
prover_claims_with_pos_evals.emplace_back(claim);
}

// Check that the Fold polynomials have been evaluated correctly in the prover
this->verify_batch_opening_pair(prover_output);
this->verify_batch_opening_pair(prover_claims_with_pos_evals);

auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);

// Compute:
// - Single opening pair: {r, \hat{a}_0}
// - d opening pairs: {r^{2^i}, \hat{a}_i} for i = 0, ..., d-1
// - 2 partially evaluated Fold polynomial commitments [Fold_{r}^(0)] and [Fold_{-r}^(0)]
// Aggregate: d+1 opening pairs and d+1 Fold poly commitments into verifier claim
// Aggregate: 2d opening pairs and 2d Fold poly commitments into verifier claim
auto verifier_claims = GeminiVerifier::reduce_verification(
multilinear_evaluation_point, mock_claims.claim_batcher, verifier_transcript);

// Check equality of the opening pairs computed by prover and verifier
for (auto [prover_claim, verifier_claim] : zip_view(prover_output, verifier_claims)) {
for (auto [prover_claim, verifier_claim] : zip_view(prover_claims_with_pos_evals, verifier_claims)) {
this->verify_opening_claim(verifier_claim, prover_claim.polynomial, ck);
ASSERT_EQ(prover_claim.opening_pair, verifier_claim.opening_pair);
}
Expand Down Expand Up @@ -102,7 +128,7 @@ TYPED_TEST(GeminiTest, DoubleWithShift)
this->execute_gemini_and_verify_claims(u, mock_claims);
}

TYPED_TEST(GeminiTest, DoubleWithShiftAndConcatenation)
TYPED_TEST(GeminiTest, DoubleWithShiftAndInterleaving)
{
auto u = this->random_evaluation_point(this->log_n);

Expand All @@ -124,23 +150,31 @@ TYPED_TEST(GeminiTest, DoubleWithShiftAndConcatenation)
*/
TYPED_TEST(GeminiTest, SoundnessRegression)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is quite bulky because the Gemini prover logic had to be deconstructed, tried to make it as illustrative and readable as possible

{
using ClaimBatcher = ClaimBatcher_<TypeParam>;
using ClaimBatch = ClaimBatcher::Batch;
using Claim = ProverOpeningClaim<TypeParam>;
using Commitment = TypeParam::AffineElement;
using Fr = TypeParam::ScalarField;
const size_t log_n = 3;
const size_t n = 8;

auto prover_transcript = NativeTranscript::prover_init_empty();
const Fr rho = prover_transcript->template get_challenge<Fr>("rho");
std::vector<Polynomial<Fr>> fold_polynomials;
fold_polynomials.reserve(log_n);

bb::Polynomial<Fr> zero_polynomial(n);
auto u = this->random_evaluation_point(this->log_n);
Polynomial<Fr> fold_0(n);
Polynomial<Fr> fold_1(n / 2);
Polynomial<Fr> fold_2(n / 4);

auto u = this->random_evaluation_point(log_n);

// Generate a random evaluation v, the prover claims that `zero_polynomial`(u) = v
Fr claimed_multilinear_eval = Fr::random_element();

// Go through the Gemini Prover steps: compute fold polynomials and their evaluations
std::vector<Fr> fold_evals;
fold_evals.reserve(log_n);
Polynomial<Fr> fold_2(2);
Polynomial<Fr> fold_1(4);

// By defining the coefficients of fold polynomials as below, a malicious prover can make sure that the values
// fold₁(r²) = 0, and hence fold₀(r), computed by the verifier, are 0. At the same time, the prover can open
Expand All @@ -158,30 +192,74 @@ TYPED_TEST(GeminiTest, SoundnessRegression)
fold_1.at(2) = -(Fr(1) - u[1]) * fold_1.at(1) * u[1].invert(); // fold₁[2] = -(1 - u₁) ⋅ fold₁[1] / u₁
fold_1.at(3) = Fr(0);

prover_transcript->template send_to_verifier("Gemini:FOLD_1", this->ck->commit(fold_1));
prover_transcript->template send_to_verifier("Gemini:FOLD_2", this->ck->commit(fold_2));

for (size_t idx = log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) {
prover_transcript->template send_to_verifier("Gemini:FOLD_" + std::to_string(idx), Commitment::one());
}

// Get Gemini evaluation challenge
const Fr gemini_r = Fr::random_element();
const Fr gemini_r = prover_transcript->template get_challenge<Fr>("Gemini:r");

// Place honest eval of fold₀(-r) to the vector of evals
fold_evals.emplace_back(Fr(0));
fold_evals.emplace_back(fold_0.evaluate(-gemini_r));

// Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, 2
std::vector<Fr> r_squares = gemini::powers_of_evaluation_challenge(gemini_r, log_n);

// Compute honest evaluations fold₁(-r²) and fold₂(-r⁴)
fold_evals.emplace_back(fold_1.evaluate(-r_squares[1]));
fold_evals.emplace_back(fold_2.evaluate(-r_squares[2]));
prover_transcript->template send_to_verifier("Gemini:a_1", fold_evals[0]);
prover_transcript->template send_to_verifier("Gemini:a_2", fold_evals[1]);
prover_transcript->template send_to_verifier("Gemini:a_3", fold_evals[2]);
for (size_t idx = log_n + 1; idx <= CONST_PROOF_SIZE_LOG_N; idx++) {
prover_transcript->template send_to_verifier("Gemini:a_" + std::to_string(idx), Fr{ 0 });
}

// Compute the powers of r used by the verifier. It is an artifact of the const proof size logic.
const std::vector<Fr> gemini_eval_challenge_powers =
gemini::powers_of_evaluation_challenge(gemini_r, CONST_PROOF_SIZE_LOG_N);

// Compute fold₀(r) as Verifier would compute it
const Fr full_a_0_pos = GeminiVerifier_<TypeParam>::compute_gemini_batched_univariate_evaluation(
log_n, claimed_multilinear_eval, u, gemini_eval_challenge_powers, fold_evals);
std::vector<Claim> prover_opening_claims;
prover_opening_claims.reserve(2 * log_n);

prover_opening_claims.emplace_back(Claim{ fold_0, { gemini_r, Fr{ 0 } } });
prover_opening_claims.emplace_back(Claim{ fold_0, { -gemini_r, Fr{ 0 } } });
prover_opening_claims.emplace_back(Claim{ fold_1, { r_squares[1], fold_1.evaluate(r_squares[1]) } });
prover_opening_claims.emplace_back(Claim{ fold_1, { -r_squares[1], fold_evals[1] } });
prover_opening_claims.emplace_back(Claim{ fold_2, { r_squares[2], fold_2.evaluate(r_squares[2]) } });
prover_opening_claims.emplace_back(Claim{ fold_2, { -r_squares[2], fold_evals[2] } });

// Check that fold₀(r) = 0. Therefore, a malicious prover could open it using the commitment to the zero
// polynomial.
EXPECT_TRUE(full_a_0_pos == Fr(0));
// Check that the Fold polynomials have been evaluated correctly in the prover
this->verify_batch_opening_pair(prover_opening_claims);

auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);

std::vector<Commitment> unshifted_commitments = { this->ck->commit(fold_0) };
std::vector<Fr> unshifted_evals = { claimed_multilinear_eval * rho.pow(0) };

ClaimBatcher claim_batcher{ .unshifted =
ClaimBatch{ RefVector(unshifted_commitments), RefVector(unshifted_evals) } };

auto verifier_claims = GeminiVerifier_<TypeParam>::reduce_verification(u, claim_batcher, verifier_transcript);

// Malicious prover could honestly prove all "negative" evaluations and several "positive evaluations". In
// particular, the evaluation of `fold_0` at r.
std::vector<size_t> matching_claim_indices{ 0, 1, 3, 4, 5 };
// However, the evaluation of `fold_1` at r^2 that the verifier computes assuming that fold has been performed
// correctly, does not match the actual evaluation of tampered fold_1 that the prover can open.
std::vector<size_t> mismatching_claim_indices = { 2 };
for (auto idx : matching_claim_indices) {
EXPECT_TRUE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair);
}

// The mismatch in claims below leads to Gemini and Shplemini Verifier rejecting the tampered proof and confirms the
// necessity of opening `fold_i` at r^{2^i} for i = 1, ..., log_n - 1.
for (auto idx : mismatching_claim_indices) {
EXPECT_FALSE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair);
}
}

template <class Curve> std::shared_ptr<typename GeminiTest<Curve>::CK> GeminiTest<Curve>::ck = nullptr;
Expand Down
Loading