Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8036d67
ultra zk passes
iakovenkos Apr 6, 2026
7ceba30
fix mega zk tests, add masking factories
iakovenkos Apr 6, 2026
31ff8f0
eccvm works
iakovenkos Apr 6, 2026
467b162
unify ZK and non-ZK virtual round paths, remove padding_indicator_arr…
iakovenkos Apr 6, 2026
2984826
batched honk is ok
iakovenkos Apr 6, 2026
24e937e
removed padding indicator array
iakovenkos Apr 6, 2026
5a6ae03
rm masking tail data
iakovenkos Apr 6, 2026
04ec473
uniform layout
iakovenkos Apr 6, 2026
4451f34
deb
iakovenkos Apr 7, 2026
4890241
databus fix
iakovenkos Apr 7, 2026
de9907e
fix tests
iakovenkos Apr 7, 2026
cc5fc28
clean up debug
iakovenkos Apr 7, 2026
da351d0
share logic
iakovenkos Apr 7, 2026
3c7d2a0
further clean up
iakovenkos Apr 7, 2026
20d9acb
gemini non-dyadic
iakovenkos Apr 7, 2026
b324157
fix tests
iakovenkos Apr 7, 2026
8e1e10a
Merge remote-tracking branch 'origin/merge-train/barretenberg' into s…
iakovenkos Apr 9, 2026
cd0f7ef
Merge remote-tracking branch 'origin/merge-train/barretenberg' into s…
iakovenkos Apr 9, 2026
25203ef
test fixes
iakovenkos Apr 9, 2026
614dc87
fix
iakovenkos Apr 9, 2026
30e426f
doc: audit all 26 ECCVM shiftable columns for masking-at-top safety
Apr 9, 2026
d0c3fc8
test: ECCVM shiftable column audit at lagrange_first row
Apr 9, 2026
844d20e
chore: corrected shiftable column audit doc + harmless/self-consisten…
Apr 9, 2026
05f50bd
chore: address review gaps in shiftable column audit
Apr 9, 2026
0cbcc87
chore: split harmless into dead vs multiset-constrained categories
Apr 9, 2026
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 @@ -4,6 +4,7 @@

#include "barretenberg/goblin/goblin.hpp"
#include "barretenberg/goblin/goblin_verifier.hpp"
#include "barretenberg/goblin/merge_prover.hpp"
#include "barretenberg/goblin/mock_circuits.hpp"
#include "barretenberg/srs/global_crs.hpp"
#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp"
Expand Down Expand Up @@ -51,7 +52,10 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test {
MergeCommitments merge_commitments;
auto t_current = goblin.op_queue->construct_current_ultra_ops_subtable_columns();
auto T_prev = goblin.op_queue->construct_previous_ultra_ops_table_columns();
CommitmentKey<curve::BN254> pcs_commitment_key(goblin.op_queue->get_ultra_ops_table_num_rows());
MergeProver::shift_table_by_disabled_rows(t_current);
MergeProver::shift_table_by_disabled_rows(T_prev);
CommitmentKey<curve::BN254> pcs_commitment_key(goblin.op_queue->get_ultra_ops_table_num_rows() +
NUM_DISABLED_ROWS_IN_SUMCHECK);
for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]);
merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ template <class RecursiveBuilder> class BoomerangRecursiveMergeVerifierTest : pu
RecursiveMergeCommitments recursive_merge_commitments;
auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
MergeProver::shift_table_by_disabled_rows(t_current);
MergeProver::shift_table_by_disabled_rows(T_prev);
for (size_t idx = 0; idx < InnerFlavor::NUM_WIRES; idx++) {
merge_commitments.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
merge_commitments.T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ class BatchedHonkTranslatorTests : public ::testing::Test {
* @param mega_zk_log_n log₂(circuit_size) of the MegaZK instance
* @param num_mega_zk_pub_inputs number of MegaZK public inputs
*/
static TranscriptManifest build_expected_batched_manifest(const size_t mega_zk_log_n,
const size_t num_mega_zk_pub_inputs)
static TranscriptManifest build_expected_batched_manifest(const size_t num_mega_zk_pub_inputs)
{
using MZK = MegaZKFlavor;
using Trans = TranslatorFlavor;
Expand Down Expand Up @@ -197,19 +196,7 @@ class BatchedHonkTranslatorTests : public ::testing::Test {
round++;

// ── Rounds 5..4+JOINT_LOG_N: joint sumcheck ──────────────────────────────
// Loop runs one extra iteration (i == JOINT_LOG_N) to place MegaZK evaluations in the
// post-sumcheck round when mega_zk_log_n == JOINT_LOG_N (no virtual rounds).
for (size_t i = 0; i <= JOINT_LOG_N; ++i) {
// MegaZK evaluations are sent immediately after the real rounds, before the first virtual
// round's univariate. In the transcript manifest they appear at the start of the round
// that contains univariate_{mega_zk_log_n} (or, when mega_zk_log_n == JOINT_LOG_N, in
// the post-sumcheck round before evaluations_translator).
if (i == mega_zk_log_n) {
m.add_entry(round, "Sumcheck:evaluations", MZK::NUM_ALL_ENTITIES);
}
if (i == JOINT_LOG_N) {
break; // No univariate/challenge for the extra iteration
}
for (size_t i = 0; i < JOINT_LOG_N; ++i) {
// Translator mini-circuit evaluations are sent after round LOG_MINI_CIRCUIT_SIZE-1
// and appear before univariate_{LOG_MINI} in the manifest.
if (i == LOG_MINI) {
Expand All @@ -223,6 +210,8 @@ class BatchedHonkTranslatorTests : public ::testing::Test {
}

// ── Post-sumcheck evaluations ─────────────────────────────────────────────
// MegaZK evaluations are sent after all sumcheck rounds (real + virtual).
m.add_entry(round, "Sumcheck:evaluations", MZK::NUM_ALL_ENTITIES);
m.add_entry(round, "Sumcheck:evaluations_translator", Trans::NUM_FULL_CIRCUIT_EVALUATIONS);
m.add_entry(round, "Libra:claimed_evaluation", Fr);
m.add_entry(round, "Libra:grand_sum_commitment", G);
Expand Down Expand Up @@ -416,7 +405,6 @@ TEST_F(BatchedHonkTranslatorTests, ProverManifestConsistency)
auto mega_zk_inst = std::make_shared<MegaZKProverInst>(mega_zk_circuit);
auto mega_zk_vk = std::make_shared<MegaZKVK>(mega_zk_inst->get_precomputed());

const size_t mega_zk_log_n = mega_zk_inst->log_dyadic_size();
const size_t num_mega_zk_pub_inputs = mega_zk_inst->num_public_inputs();

// Prove with manifest tracking enabled.
Expand All @@ -427,7 +415,7 @@ TEST_F(BatchedHonkTranslatorTests, ProverManifestConsistency)
[[maybe_unused]] auto __ = prover.prove(translator_key);

auto prover_manifest = prover_transcript->get_manifest();
auto expected_manifest = build_expected_batched_manifest(mega_zk_log_n, num_mega_zk_pub_inputs);
auto expected_manifest = build_expected_batched_manifest(num_mega_zk_pub_inputs);

ASSERT_EQ(prover_manifest.size(), expected_manifest.size()) << "Manifest round count mismatch";
for (size_t round = 0; round < expected_manifest.size(); ++round) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp"
#include "barretenberg/polynomials/gate_separator.hpp"
#include "barretenberg/polynomials/row_disabling_polynomial.hpp"
#include "barretenberg/sumcheck/masking_tail_data.hpp"
#include "barretenberg/translator_vm/translator_prover.hpp"

namespace bb {
Expand Down Expand Up @@ -59,9 +58,9 @@ void BatchedHonkTranslatorProver::execute_translator_oink()
*
* For rounds mega_zk_log_n..JOINT_LOG_N-1 ("virtual rounds"), the MegaZK polynomials are treated as
* zero-padded to 2^JOINT_LOG_N. The contribution is computed via compute_virtual_contribution
* (evaluating the relation at the only non-zero edge), scaled by the RDP factor from real rounds.
* After each virtual round, the partially-evaluated MegaZK polynomials are updated by multiplying
* by (1 - u_k), so the final claimed evaluations include the tau factor ∏(1 - u_k).
* (evaluating the relation at the only non-zero edge), multiplied by the per-round (1-L) factor
* from the row-disabling polynomial. Libra masking covers all JOINT_LOG_N rounds uniformly.
* After each virtual round, PE values are folded by (1-u_k) for zero-extension.
*/
void BatchedHonkTranslatorProver::execute_joint_sumcheck_rounds()
{
Expand Down Expand Up @@ -145,17 +144,14 @@ void BatchedHonkTranslatorProver::execute_joint_sumcheck_rounds()
translator_round.round_size >>= 1;
};

auto& masking_tail = mega_zk_inst->masking_tail_data;

// Per-round helper: compute U_joint = U_MZK + α^{K_H}·U_translator from given polynomial
// sources, add Libra masking, send to verifier, and return the round challenge.
// hpolys/tpolys are the full tables on round 0, the partial-eval tables on subsequent rounds.
auto do_round = [&](auto& hpolys, auto& tpolys, size_t round_idx) -> FF {
U_joint = SumcheckRoundUnivariate::zero();

auto U_H = mega_zk_round.compute_univariate(hpolys, mega_zk_params, gate_sep, mega_zk_alphas);
U_H += mega_zk_round.compute_disabled_contribution(
hpolys, mega_zk_params, gate_sep, mega_zk_alphas, rdp, masking_tail);
U_H += mega_zk_round.compute_disabled_contribution(hpolys, mega_zk_params, gate_sep, mega_zk_alphas, rdp);
U_joint += U_H;

auto U_T =
Expand All @@ -175,64 +171,28 @@ void BatchedHonkTranslatorProver::execute_joint_sumcheck_rounds()
MegaZKSumcheck::partially_evaluate(mega_zk_polys, mega_zk_partial, u);
TransSumcheck::partially_evaluate(translator_polys, translator_partial, u);
rdp.update_evaluations(u, 0);
masking_tail.fold_masking_values(u, 0, mega_zk_round.round_size, &mega_zk_polys);
mega_zk_round.round_size >>= 1;
mega_zk_round.excluded_tail_size = 2; // After round 0, disabled zone collapses to 1 edge pair
mega_zk_round.excluded_head_size = 2; // After round 0, disabled zone collapses to 1 edge pair
update_round_state(0, u);
}

// ==================== Real rounds 1..mega_zk_log_n-1 ====================
for (size_t round_idx = 1; round_idx < mega_zk_log_n; round_idx++) {
const FF u = do_round(mega_zk_partial, translator_partial, round_idx);
// Fold masking values BEFORE partially_evaluate (rounds 2+ read PE at active positions)
masking_tail.fold_masking_values(u, round_idx, mega_zk_round.round_size, &mega_zk_partial);
MegaZKSumcheck::partially_evaluate_in_place(mega_zk_partial, u);
TransSumcheck::partially_evaluate_in_place(translator_partial, u);
rdp.update_evaluations(u, round_idx);
mega_zk_round.round_size >>= 1;
update_round_state(round_idx, u);
}

// Capture RDP scalar after all real rounds for use in virtual rounds.
// rdp_scalar = RDP(u_0,...,u_{d-1}) = 1 - u_2*...*u_{d-1}.
const FF rdp_scalar = FF(1) - rdp.eval_at_1;

// Send MegaZK circuit evaluations immediately after the real rounds.
// These are P_j(u_0,...,u_{d-1}) — the natural d-variable evaluations without the tau factor.
// The verifier will extend them by zero (multiply by τ = ∏(1-u_k)) after drawing virtual-round challenges.
// This eliminates any prover freedom in the zero-padded region: the extension is verifier-determined.
for (auto [eval, poly] : zip_view(mega_zk_claimed_evals.get_all(), mega_zk_partial.get_all())) {
eval = poly[0];
}

// Apply masking tail corrections: short witness polys have zeros at tail positions,
// so claimed evals need Lagrange-basis corrections using the first mega_zk_log_n challenges.
if (masking_tail.is_active()) {
auto real_challenges = std::span<const FF>(joint_challenge.data(), mega_zk_log_n);
masking_tail.apply_claimed_eval_corrections(mega_zk_claimed_evals, real_challenges);

// Write corrected values back into mega_zk_partial so that compute_virtual_contribution
// in virtual rounds uses the corrected evaluations.
for (auto [eval, poly] : zip_view(mega_zk_claimed_evals.get_all(), mega_zk_partial.get_all())) {
if (poly.end_index() > 0) {
poly.at(0) = eval;
}
}
}

transcript->send_to_verifier("Sumcheck:evaluations", mega_zk_claimed_evals.get_all());

// ==================== Virtual rounds mega_zk_log_n..JOINT_LOG_N-1 ====================
// The MegaZK polynomials are zero-padded beyond 2^mega_zk_log_n. The virtual contribution
// is compute_virtual_contribution * rdp_scalar. The polynomial values are updated by
// (1-u_k) after each round for the virtual contribution computation.
// MegaZK contributes a virtual (zero-extended) univariate with RDP factor; translator contributes a real round.
for (size_t round_idx = mega_zk_log_n; round_idx < JOINT_LOG_N; round_idx++) {
U_joint = SumcheckRoundUnivariate::zero();

auto U_H =
mega_zk_round.compute_virtual_contribution(mega_zk_partial, mega_zk_params, gate_sep, mega_zk_alphas);
U_H *= rdp_scalar;
U_joint += U_H;
U_joint += MegaZKSumcheck::compute_virtual_round_univariate(
mega_zk_round, mega_zk_partial, mega_zk_params, gate_sep, mega_zk_alphas, rdp);

auto U_T = translator_round.compute_univariate(
translator_partial, translator_relation_parameters, gate_sep, translator_alphas);
Expand All @@ -241,31 +201,33 @@ void BatchedHonkTranslatorProver::execute_joint_sumcheck_rounds()
}
U_joint += U_T;

// send_round adds libra masking, sends univariate, and returns the challenge
const FF u = send_round(round_idx);

// Virtual: poly values *= (1 - u_k) for the next virtual contribution computation.
for (auto& poly : mega_zk_partial.get_all()) {
if (poly.end_index() > 0) {
poly.at(0) *= (FF(1) - u);
}
}
MegaZKSumcheck::fold_for_zero_extension(mega_zk_partial, u);
TransSumcheck::partially_evaluate_in_place(translator_partial, u);
rdp.update_evaluations(u, round_idx);
update_round_state(round_idx, u);
}

// Finalize committed sumcheck: populate the last round's evaluation at the final challenge.
handler.finalize_last_round(JOINT_LOG_N, U_joint, joint_challenge.back());
round_univariates_list = std::move(handler.round_univariates);
round_evaluations_list = std::move(handler.round_evaluations);

// Extract and send MegaZK evaluations after all rounds — full N-variable evaluations.
for (auto [eval, poly] : zip_view(mega_zk_claimed_evals.get_all(), mega_zk_partial.get_all())) {
eval = poly[0];
}
transcript->send_to_verifier("Sumcheck:evaluations", mega_zk_claimed_evals.get_all());

// Extract and send translator evaluations after all rounds.
for (auto [eval, poly] : zip_view(trans_claimed_evals.get_all(), translator_partial.get_all())) {
eval = poly[0];
}
transcript->send_to_verifier("Sumcheck:evaluations_translator",
TranslatorFlavor::get_full_circuit_evaluations(trans_claimed_evals));

// Compute and send the claimed Libra evaluation.
// Compute and send the claimed Libra evaluation (covers all JOINT_LOG_N rounds).
claimed_libra_evaluation = zk_sumcheck_data.constant_term;
for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) {
claimed_libra_evaluation += libra_eval;
Expand Down Expand Up @@ -317,11 +279,6 @@ void BatchedHonkTranslatorProver::execute_joint_pcs()
auto joint_shifted = concatenate(mega_zk_shifted, trans_shifted);
polynomial_batcher.set_to_be_shifted_by_one(joint_shifted);

// Register MegaZK masking tails with the joint batcher
if (mega_zk_inst->masking_tail_data.is_active()) {
mega_zk_inst->masking_tail_data.add_tails_to_batcher(mega_zk_inst->polynomials, polynomial_batcher);
}

const OpeningClaim prover_opening_claim =
ShpleminiProver_<Curve>::prove(joint_circuit_size,
polynomial_batcher,
Expand Down
Loading
Loading