Skip to content

Commit da8cd88

Browse files
authored
chore: minor fixes pt. 2 (#22138)
Fix several issues discovered by Claude
1 parent de2ac63 commit da8cd88

8 files changed

Lines changed: 58 additions & 97 deletions

File tree

barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,7 @@ template <typename Curve> class GeminiProver_ {
267267

268268
static std::vector<Polynomial> compute_fold_polynomials(const size_t log_n,
269269
std::span<const Fr> multilinear_challenge,
270-
const Polynomial& A_0,
271-
const bool& has_zk = false);
270+
const Polynomial& A_0);
272271

273272
static std::vector<Claim> construct_univariate_opening_claims(const size_t log_n,
274273
Polynomial&& A_0_pos,

barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove(
6666
Polynomial A_0 = polynomial_batcher.compute_batched(rho);
6767

6868
// Construct the d-1 Gemini foldings of A₀(X)
69-
std::vector<Polynomial> fold_polynomials = compute_fold_polynomials(log_n, multilinear_challenge, A_0, has_zk);
69+
std::vector<Polynomial> fold_polynomials = compute_fold_polynomials(log_n, multilinear_challenge, A_0);
7070

7171
// If virtual_log_n >= log_n, pad the fold commitments with dummy group elements [1]_1.
7272
for (size_t l = 0; l < virtual_log_n - 1; l++) {
7373
std::string label = "Gemini:FOLD_" + std::to_string(l + 1);
74-
// When has_zk is true, we are sending commitments to 0. Seems to work, but maybe brittle.
74+
// Virtual-round fold polynomials are constant; their commitments are zeroed by the verifier.
7575
transcript->send_to_verifier(label, commitment_key.commit(fold_polynomials[l]));
7676
}
7777
const Fr r_challenge = transcript->template get_challenge<Fr>("Gemini:r");
@@ -108,7 +108,7 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove(
108108
*/
109109
template <typename Curve>
110110
std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::compute_fold_polynomials(
111-
const size_t log_n, std::span<const Fr> multilinear_challenge, const Polynomial& A_0, const bool& has_zk)
111+
const size_t log_n, std::span<const Fr> multilinear_challenge, const Polynomial& A_0)
112112
{
113113
BB_BENCH_NAME("Gemini::compute_fold_polynomials");
114114
BB_ASSERT_GTE(log_n, size_t(2), "Gemini folding requires at least 4-element polynomials");
@@ -156,25 +156,23 @@ std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::com
156156
A_l = A_l_fold;
157157
}
158158

159-
// Perform virtual rounds.
160-
// After the first `log_n - 1` rounds, the prover's `fold` univariates stabilize. With ZK, the verifier multiplies
161-
// the evaluations by 0, otherwise, when `virtual_log_n > log_n`, the prover honestly computes and sends the
162-
// constant folds.
159+
// Virtual rounds (indices log_n .. virtual_log_n - 1).
160+
// After real folding, the fold polynomials are constant. Since each constant polynomial evaluates to its own
161+
// value at every point, (f(X) - f(x)) / (X - x) = 0, so these contribute nothing to the Shplonk quotient Q(X).
162+
// On the verifier side, padding_indicator_array zeros their contributions independently.
163163
const auto& last = fold_polynomials.back();
164164
const Fr u_last = multilinear_challenge[log_n - 1];
165165
const Fr final_eval = last.at(0) + u_last * (last.at(1) - last.at(0));
166166
Polynomial const_fold(1);
167-
// Temporary fix: when we're running a zk proof, the verifier uses a `padding_indicator_array`. So the evals in
168-
// rounds past `log_n - 1` will be ignored. Hence the prover also needs to ignore them, otherwise Shplonk will fail.
169-
const_fold.at(0) = final_eval * Fr(static_cast<int>(!has_zk));
167+
const_fold.at(0) = final_eval;
170168
fold_polynomials.emplace_back(const_fold);
171169

172170
// FOLD_{log_n+1}, ..., FOLD_{d_v-1}
173171
Fr tail = Fr(1);
174172
for (size_t k = log_n; k < virtual_log_n - 1; ++k) {
175173
tail *= (Fr(1) - multilinear_challenge[k]); // multiply by (1 - u_k)
176174
Polynomial next_const(1);
177-
next_const.at(0) = final_eval * tail * Fr(static_cast<int>(!has_zk));
175+
next_const.at(0) = final_eval * tail;
178176
fold_polynomials.emplace_back(next_const);
179177
}
180178

barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,10 @@ template <typename Curve, bool HasZK = false> class ShpleminiVerifier_ {
368368
libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation);
369369
}
370370

371-
// Currently, only used in ECCVM
371+
// Used in ECCVM and BatchedHonkTranslator. The nu power offset in batch_sumcheck_round_claims
372+
// assumes ZK claims (NUM_SMALL_IPA_EVALUATIONS) precede sumcheck round claims in the batching order.
372373
if (committed_sumcheck) {
374+
BB_ASSERT(HasZK, "committed sumcheck requires ZK for correct nu power indexing");
373375
batch_sumcheck_round_claims(commitments,
374376
scalars,
375377
constant_term_accumulator,
@@ -513,18 +515,28 @@ template <typename Curve, bool HasZK = false> class ShpleminiVerifier_ {
513515
}
514516

515517
// Erase the duplicate entries (higher-index range first to preserve lower indices)
516-
auto erase_range = [&](size_t start, size_t count) {
518+
auto erase_range = [&](size_t duplicate_start, size_t original_start, size_t count) {
517519
for (size_t i = 0; i < count; ++i) {
518-
scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(start));
519-
commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(start));
520+
// Verify the commitment being erased matches its original (native only).
521+
// Each erase shifts elements down, so duplicate_start always points to the
522+
// next duplicate; the original at original_start + i is unaffected since
523+
// we erase higher-index ranges first.
524+
if constexpr (!Curve::is_stdlib_type) {
525+
BB_ASSERT(commitments[duplicate_start] == commitments[original_start + i],
526+
"remove_repeated_commitments: commitment mismatch at duplicate index " +
527+
std::to_string(duplicate_start) + " vs original index " +
528+
std::to_string(original_start + i));
529+
}
530+
scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(duplicate_start));
531+
commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(duplicate_start));
520532
}
521533
};
522534
if (second_duplicate_start > first_duplicate_start) {
523-
erase_range(second_duplicate_start, r2.count);
524-
erase_range(first_duplicate_start, r1.count);
535+
erase_range(second_duplicate_start, second_original_start, r2.count);
536+
erase_range(first_duplicate_start, first_original_start, r1.count);
525537
} else {
526-
erase_range(first_duplicate_start, r1.count);
527-
erase_range(second_duplicate_start, r2.count);
538+
erase_range(first_duplicate_start, first_original_start, r1.count);
539+
erase_range(second_duplicate_start, second_original_start, r2.count);
528540
}
529541
}
530542

barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -171,29 +171,24 @@ template <typename Curve> class ShplonkProver_ {
171171
// s.t. G(r) = 0
172172
Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X)
173173

174-
// G₀ = ∑ⱼ νʲ ⋅ vⱼ / ( z − xⱼ )
175174
Fr current_nu = Fr::one();
176-
Polynomial tmp(G.size());
177175
size_t idx = 0;
178176

179177
size_t fold_idx = 0;
180-
for (auto& claim : opening_claims) {
178+
for (const auto& claim : opening_claims) {
181179

182180
if (claim.gemini_fold) {
183-
tmp = claim.polynomial;
184-
tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx++];
185-
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ )
186-
// G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ )
187-
G.add_scaled(tmp, -scaling_factor);
181+
// G -= νʲ ⋅ ( fⱼ(X) − vⱼ₊) / ( z + xⱼ ), where vⱼ₊ is the positive fold evaluation
182+
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z + xⱼ )
183+
G.add_scaled(claim.polynomial, -scaling_factor);
184+
G.at(0) = G[0] + scaling_factor * gemini_fold_pos_evaluations[fold_idx++];
188185

189186
current_nu *= nu_challenge;
190187
}
191-
// tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ )
192-
claim.polynomial.at(0) = claim.polynomial[0] - claim.opening_pair.evaluation;
193-
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ )
194-
195188
// G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ )
189+
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ )
196190
G.add_scaled(claim.polynomial, -scaling_factor);
191+
G.at(0) = G[0] + scaling_factor * claim.opening_pair.evaluation;
197192

198193
current_nu *= nu_challenge;
199194
}
@@ -203,22 +198,18 @@ template <typename Curve> class ShplonkProver_ {
203198
current_nu = nu_challenge.pow(2 * virtual_log_n);
204199
}
205200

206-
for (auto& claim : libra_opening_claims) {
207-
// Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ )
208-
claim.polynomial.at(0) = claim.polynomial[0] - claim.opening_pair.evaluation;
201+
for (const auto& claim : libra_opening_claims) {
202+
// G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ )
209203
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ )
210-
211-
// Add the claim quotient to the batched quotient polynomial
212204
G.add_scaled(claim.polynomial, -scaling_factor);
205+
G.at(0) = G[0] + scaling_factor * claim.opening_pair.evaluation;
213206
current_nu *= nu_challenge;
214207
}
215208

216-
for (auto& claim : sumcheck_opening_claims) {
217-
claim.polynomial.at(0) = claim.polynomial[0] - claim.opening_pair.evaluation;
209+
for (const auto& claim : sumcheck_opening_claims) {
218210
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ )
219-
220-
// Add the claim quotient to the batched quotient polynomial
221211
G.add_scaled(claim.polynomial, -scaling_factor);
212+
G.at(0) = G[0] + scaling_factor * claim.opening_pair.evaluation;
222213
current_nu *= nu_challenge;
223214
}
224215
// Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X)

barretenberg/cpp/src/barretenberg/crypto/poseidon2/sponge/sponge.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ namespace bb::crypto {
1717

1818
/**
1919
* @brief Implements a cryptographic sponge over prime fields.
20-
* Implements the sponge specification from the Community Cryptographic Specification Project
21-
* see https://github.com/C2SP/C2SP/blob/792c1254124f625d459bfe34417e8f6bdd02eb28/poseidon-sponge.md
22-
* (Note: this spec was not accepted into the C2SP repo, we might want to reference something else!)
20+
* Sponge construction follows the Duplex Sponge model (https://keccak.team/files/SpongeDuplex.pdf).
21+
* Domain separation uses IV = (input_length << 64) per Section 4.2 of the Poseidon paper
22+
* (https://eprint.iacr.org/2019/458.pdf). Permutation is Poseidon2
23+
* (https://eprint.iacr.org/2023/323.pdf).
2324
*
2425
* Note: If we ever use this sponge class for more than 1 hash functions, we should move this out of `poseidon2`
2526
* and into its own directory

barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,8 @@ template <typename Flavor> typename Flavor::ProverPolynomials create_satisfiable
7171
// For ZK flavors: add randomness to the last rows (which will be masked by row-disabling polynomial)
7272
// These rows don't need to satisfy the relation because they're disabled
7373
if constexpr (Flavor::HasZK) {
74-
constexpr size_t NUM_DISABLED_ROWS = 3; // Matches the number of disabled rows in ZK sumcheck
75-
if (circuit_size > NUM_DISABLED_ROWS) {
76-
for (size_t i = circuit_size - NUM_DISABLED_ROWS; i < circuit_size; ++i) {
74+
if (circuit_size > NUM_DISABLED_ROWS_IN_SUMCHECK) {
75+
for (size_t i = circuit_size - NUM_DISABLED_ROWS_IN_SUMCHECK; i < circuit_size; ++i) {
7776
full_polynomials.w_l.at(i) = FF::random_element();
7877
full_polynomials.w_r.at(i) = FF::random_element();
7978
full_polynomials.w_o.at(i) = FF::random_element();

barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -284,43 +284,6 @@ template <typename Flavor> class SumcheckProverRound {
284284
size_t size;
285285
};
286286

287-
/**
288-
* @brief Helper struct that will, given a vector of BlockOfContiguousRows, return the edge indices that correspond
289-
* to the nonzero rows
290-
*/
291-
struct RowIterator {
292-
const std::vector<BlockOfContiguousRows>* blocks;
293-
size_t current_block_index = 0;
294-
size_t current_block_count = 0;
295-
RowIterator(const std::vector<BlockOfContiguousRows>& _blocks, size_t starting_index = 0)
296-
: blocks(&_blocks)
297-
{
298-
size_t count = 0;
299-
for (size_t i = 0; i < blocks->size(); ++i) {
300-
const BlockOfContiguousRows block = blocks->at(i);
301-
if (count + (block.size / 2) > starting_index) {
302-
current_block_index = i;
303-
current_block_count = (starting_index - count) * 2;
304-
break;
305-
}
306-
count += (block.size / 2);
307-
}
308-
}
309-
310-
size_t get_next_edge()
311-
{
312-
const BlockOfContiguousRows& block = blocks->at(current_block_index);
313-
size_t edge = block.starting_edge_idx + current_block_count;
314-
if (current_block_count + 2 >= block.size) {
315-
current_block_index += 1;
316-
current_block_count = 0;
317-
} else {
318-
current_block_count += 2;
319-
}
320-
return edge;
321-
}
322-
};
323-
324287
/**
325288
* @brief Compute the number of unskippable rows we must iterate over
326289
* @details Some circuits have a circuit size much larger than the number of used rows (ECCVM, Translator).

barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "barretenberg/polynomials/polynomial.hpp"
1212
#include "barretenberg/polynomials/univariate.hpp"
1313
#include <array>
14+
#include <tuple>
1415
#include <vector>
1516

1617
namespace bb {
@@ -76,8 +77,7 @@ template <typename Flavor> struct ZKSumcheckData {
7677
transcript->send_to_verifier("Libra:concatenation_commitment", libra_commitment);
7778
}
7879
// Compute the total sum of the Libra polynomials
79-
libra_scaling_factor = FF(1);
80-
libra_total_sum = compute_libra_total_sum(libra_univariates, libra_scaling_factor, constant_term);
80+
std::tie(libra_total_sum, libra_scaling_factor) = compute_libra_total_sum(libra_univariates, constant_term);
8181

8282
// Send the Libra total sum to the transcript
8383
transcript->send_to_verifier("Libra:Sum", libra_total_sum);
@@ -106,13 +106,12 @@ template <typename Flavor> struct ZKSumcheckData {
106106
: constant_term(FF::random_element())
107107
, libra_univariates(generate_libra_univariates(multivariate_d, univariate_length))
108108
, log_circuit_size(multivariate_d)
109-
, libra_scaling_factor(FF(1))
110109
, libra_challenge(FF::random_element())
111-
, libra_total_sum(compute_libra_total_sum(libra_univariates, libra_scaling_factor, constant_term))
112-
, libra_running_sum(libra_total_sum * libra_challenge)
113110
, univariate_length(univariate_length)
114111

115112
{
113+
std::tie(libra_total_sum, libra_scaling_factor) = compute_libra_total_sum(libra_univariates, constant_term);
114+
libra_running_sum = libra_total_sum * libra_challenge;
116115
setup_auxiliary_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum);
117116
}
118117
/**
@@ -137,23 +136,22 @@ template <typename Flavor> struct ZKSumcheckData {
137136
* the Boolean hypercube.
138137
*
139138
* @param libra_univariates
140-
* @param scaling_factor
141-
* @return FF
139+
* @param constant_term
140+
* @return A pair of (total_sum, scaling_factor), where scaling_factor = 2^{d-1}.
142141
*/
143-
static FF compute_libra_total_sum(const std::vector<Polynomial<FF>>& libra_univariates,
144-
FF& scaling_factor,
145-
const FF& constant_term)
142+
static std::pair<FF, FF> compute_libra_total_sum(const std::vector<Polynomial<FF>>& libra_univariates,
143+
const FF& constant_term)
146144
{
147145
FF total_sum = 0;
148-
scaling_factor *= one_half;
146+
FF scaling_factor = one_half;
149147

150148
for (auto& univariate : libra_univariates) {
151149
total_sum += univariate.at(0) + univariate.evaluate(FF(1));
152150
scaling_factor *= 2;
153151
}
154152
total_sum *= scaling_factor;
155153

156-
return total_sum + constant_term * (1 << libra_univariates.size());
154+
return { total_sum + constant_term * (1 << libra_univariates.size()), scaling_factor };
157155
}
158156

159157
/**

0 commit comments

Comments
 (0)