Skip to content

Commit 4beae29

Browse files
authored
feat: merge-train/barretenberg (#17127)
BEGIN_COMMIT_OVERRIDE chore: ECCVM audit skip conditions (#17108) END_COMMIT_OVERRIDE
2 parents d1d3d50 + 88340ef commit 4beae29

File tree

4 files changed

+62
-25
lines changed

4 files changed

+62
-25
lines changed

barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,26 @@ ECCVMCircuitBuilder generate_circuit(numeric::RNG* engine = nullptr)
6666
return builder;
6767
}
6868

69-
ECCVMCircuitBuilder generate_zero_circuit([[maybe_unused]] numeric::RNG* engine = nullptr)
69+
// returns a CircuitBuilder consisting of mul_add ops of the following form: either 0*g, for a group element, or
70+
// x * e, where x is a scalar and e is the identity element of the group.
71+
ECCVMCircuitBuilder generate_zero_circuit([[maybe_unused]] numeric::RNG* engine = nullptr, bool zero_scalars = 1)
7072
{
7173
using Curve = curve::BN254;
7274
using G1 = Curve::Element;
7375
using Fr = Curve::ScalarField;
7476

7577
std::shared_ptr<ECCOpQueue> op_queue = std::make_shared<ECCOpQueue>();
76-
[[maybe_unused]] G1 a = G1::random_element(engine);
7778

78-
[[maybe_unused]] Fr x = Fr::random_element(engine);
79-
for (auto i = 0; i < 8; i++) {
80-
op_queue->mul_accumulate(Curve::Group::affine_point_at_infinity, 0);
79+
if (!zero_scalars) {
80+
for (auto i = 0; i < 8; i++) {
81+
Fr x = Fr::random_element(engine);
82+
op_queue->mul_accumulate(Curve::Group::affine_point_at_infinity, x);
83+
}
84+
} else {
85+
for (auto i = 0; i < 8; i++) {
86+
G1 g = G1::random_element(engine);
87+
op_queue->mul_accumulate(g, 0);
88+
}
8189
}
8290
op_queue->merge();
8391

@@ -113,9 +121,23 @@ void complete_proving_key_for_test(bb::RelationParameters<FF>& relation_paramete
113121
gate_challenges[idx] = FF::random_element();
114122
}
115123
}
116-
TEST_F(ECCVMTests, Zeroes)
124+
TEST_F(ECCVMTests, ZeroesCoefficients)
117125
{
118-
ECCVMCircuitBuilder builder = generate_zero_circuit(&engine);
126+
ECCVMCircuitBuilder builder = generate_zero_circuit(&engine, 1);
127+
128+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
129+
ECCVMProver prover(builder, prover_transcript);
130+
ECCVMProof proof = prover.construct_proof();
131+
132+
std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
133+
ECCVMVerifier verifier(verifier_transcript);
134+
bool verified = verifier.verify_proof(proof);
135+
136+
ASSERT_TRUE(verified);
137+
}
138+
TEST_F(ECCVMTests, PointAtInfinity)
139+
{
140+
ECCVMCircuitBuilder builder = generate_zero_circuit(&engine, 0);
119141

120142
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
121143
ECCVMProver prover(builder, prover_transcript);

barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,33 +1018,37 @@ class ECCVMFlavor {
10181018
};
10191019

10201020
/**
1021-
* @brief When evaluating the sumcheck protocol - can we skip evaluation of all relations for a given row?
1021+
* @brief When evaluating the sumcheck protocol - can we skip evaluation of _all_ relations for a given row? This
1022+
* is purely a prover-side optimization.
10221023
*
10231024
* @details When used in ClientIVC, the ECCVM has a large fixed size, which is often not fully utilized.
1024-
* If a row is completely empty, the values of z_perm and z_perm_shift will match,
1025-
* we can use this as a proxy to determine if we can skip Sumcheck::compute_univariate_with_row_skipping
1025+
* If a row is completely empty, the values of `z_perm` and `z_perm_shift` will match,
1026+
* we can use this as a proxy to determine if we can skip `Sumcheck::compute_univariate_with_row_skipping`.
1027+
* In fact, here are several other conditions that need to be checked to see if we can skip the computation
1028+
* of all relations in the row.
10261029
**/
10271030
template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates, typename EdgeType>
10281031
static bool skip_entire_row([[maybe_unused]] const ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
10291032
[[maybe_unused]] const EdgeType edge_idx)
10301033
{
1031-
// skip conditions. TODO: add detailed commentary during audit.
1034+
// SKIP CONDITIONS:
10321035
// The most important skip condition is that `z_perm == z_perm_shift`. This implies that none of the wire values
10331036
// for the present input are involved in non-trivial copy constraints. Edge cases where nonzero rows do not
10341037
// contribute to permutation:
10351038
//
10361039
// 1: If `lagrange_last != 0`, the permutation polynomial identity is updated even if
1037-
// z_perm == z_perm_shift
1040+
// z_perm == z_perm_shift. Therefore, we must force it to be zero.
10381041
//
10391042
// 2: The final MSM row won't add to the permutation but still has polynomial identitiy
10401043
// contributions. This is because the permutation argument uses the SHIFTED msm columns when performing
1041-
// lookups i.e. `polynomials.msm_accumulator_x[last_edge_idx] will change z_perm[last_edge_idx - 1] and
1042-
// z_perm_shift[last_edge_idx - 1]
1044+
// lookups i.e. `msm_accumulator_x[last_edge_idx]` will change `z_perm[last_edge_idx - 1]` and
1045+
// `z_perm_shift[last_edge_idx - 1]`
10431046
//
1044-
// 3. The value of `transcript_mul` can be non-zero at the end of an MSM of points-at-infinity, which will
1045-
// cause `full_msm_count` to be non-zero while `transcript_msm_count` vanishes.
1047+
// 3. The value of `transcript_mul` is non-zero at the end of an MSM of points-at-infinity, which will
1048+
// cause `full_msm_count` to be non-zero while `transcript_msm_count` vanishes. We therefore force
1049+
// transcript_mul == 0 as a skip-row condition.
10461050
//
1047-
// 4. For similar reasons, we must add that `transcript_op==0`.
1051+
// 4: We also force that `transcript_op==0`.
10481052
return (polynomials.z_perm[edge_idx] == polynomials.z_perm_shift[edge_idx]) &&
10491053
(polynomials.z_perm[edge_idx + 1] == polynomials.z_perm_shift[edge_idx + 1]) &&
10501054
(polynomials.lagrange_last[edge_idx] == 0 && polynomials.lagrange_last[edge_idx + 1]) == 0 &&

barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,27 @@ template <typename FF_> class ECCVMSetRelationImpl {
2222
22, // grand product construction sub-relation
2323
3 // left-shiftable polynomial sub-relation
2424
};
25-
25+
// prover optimization to allow for skipping the computation of sub-relations at certain points in sumcheck.
2626
template <typename AllEntities> inline static bool skip(const AllEntities& in)
2727
{
28-
// If z_perm == z_perm_shift, this implies that none of the wire values for the present input are involved in
29-
// non-trivial copy constraints. The value of `transcript_mul` can be non-zero at the end of an MSM of
30-
// points-at-infinity, which will cause `full_msm_count` to be non-zero while `transcript_msm_count` vanishes.
31-
// Therefore, we add this as a skip condition.
28+
// For the first accumulator in the set relation, the added-on term is 0 if the following vanishes:
29+
//
30+
// `(z_perm + lagrange_first) * numerator_evaluation - (z_perm_shift + lagrange_last) * denominator_evaluation`,
31+
//
32+
// i.e., if z_perm is well-formed.
33+
//
34+
// For the second accumulator in the set relation, the added-on term is 0 if the following vanishes:
35+
//
36+
// `lagrange_last_short * z_perm_shift_short`
37+
//
38+
// To know when we can skip this computation (i.e., when it is "automatically" 0), most cases are handled by the
39+
// condtion `z_perm == z_perf_shift`. In most circumstances, this implies that with overwhelming probability,
40+
// none of the wire values for the present input are involved in non-trivial copy constraints.
41+
//
42+
// There are two other edge-cases we need to check for to know we can skip the computation. First,
43+
// `transcript_mul` can be 1 even though the multiplication is "degenerate" (and not handled by the MSM table):
44+
// this holds if either the scalar is 0 or the point is the neutral element. Therefore we force this. Second, we
45+
// must force lagrange_last == 0.
3246
return (in.z_perm - in.z_perm_shift).is_zero() && in.transcript_mul.is_zero() && in.lagrange_last.is_zero();
3347
}
3448

barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,6 @@ Accumulator ECCVMSetRelationImpl<FF>::compute_grand_product_numerator(const AllE
144144
// if `precompute_select == 1`, don't change the numerator. if it is 0, then to get the grand product argument
145145
// to work (as we have zero-padded the rows of the MSM table), we must multiply by
146146
// `eccvm_set_permutation_delta` == (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²)
147-
// if `precompute_select == 1`, don't change the numerator. if it is 0, then to get the grand product argument
148-
// to work (as we have zero-padded the rows of the MSM table), we must multiply by
149-
// `eccvm_set_permutation_delta` == (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²)
150147
numerator *= precompute_select * (-eccvm_set_permutation_delta + 1) + eccvm_set_permutation_delta; // degree-7
151148
}
152149

0 commit comments

Comments
 (0)