Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_transcript_short_relation_impl.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8
10
11namespace bb {
12
13template <typename FF>
14template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
15void ECCVMTranscriptShortRelationImpl<FF>::accumulate(ContainerOverSubrelations& accumulator,
16 const AllEntities& in,
17 const Parameters& /*unused*/,
18 const FF& scaling_factor)
19{
20 // "Core" accumulator type — used by LAMBDA_RELATION / ACC_X/Y_UPDATE / ACC_EMPTY_UPDATE, which share several
21 // promoted intermediates (result_is_lhs/rhs/inf, opcode_is_zero).
24
25 // Per-subrelation accumulator types for tightened partial lengths.
32
33 const auto z1 = View(in.transcript_z1);
34 const auto z2 = View(in.transcript_z2);
35 const auto z1_zero = View(in.transcript_z1zero);
36 const auto z2_zero = View(in.transcript_z2zero);
37 const auto op = View(in.transcript_op);
38 const auto q_add = View(in.transcript_add);
39 const auto q_mul = View(in.transcript_mul);
40 const auto q_mul_shift = View(in.transcript_mul_shift);
41 const auto q_eq = View(in.transcript_eq);
42 const auto msm_transition = View(in.transcript_msm_transition);
43 const auto msm_count = View(in.transcript_msm_count);
44 const auto msm_count_shift = View(in.transcript_msm_count_shift);
45 const auto pc = View(in.transcript_pc);
46 const auto pc_shift = View(in.transcript_pc_shift);
47 const auto transcript_accumulator_x_shift = View(in.transcript_accumulator_x_shift);
48 const auto transcript_accumulator_y_shift = View(in.transcript_accumulator_y_shift);
49 const auto transcript_accumulator_x = View(in.transcript_accumulator_x);
50 const auto transcript_accumulator_y = View(in.transcript_accumulator_y);
51 const auto msm_count_zero_at_transition = View(in.transcript_msm_count_zero_at_transition);
52 const auto msm_count_at_transition_inverse = View(in.transcript_msm_count_at_transition_inverse);
53 const auto transcript_msm_x = View(in.transcript_msm_intermediate_x);
54 const auto transcript_msm_y = View(in.transcript_msm_intermediate_y);
55 const auto transcript_Px = View(in.transcript_Px);
56 const auto transcript_Py = View(in.transcript_Py);
57 const auto transcript_accumulator_not_empty = View(in.transcript_accumulator_not_empty);
58 const auto is_accumulator_empty = -transcript_accumulator_not_empty + FF(1);
59 const auto lagrange_first = View(in.lagrange_first);
60 const auto lagrange_last = View(in.lagrange_last);
61 const auto is_accumulator_empty_shift = -View(in.transcript_accumulator_not_empty_shift) + FF(1);
62 const auto q_reset_accumulator = View(in.transcript_reset_accumulator);
63 const auto lagrange_second = View(in.lagrange_second);
64 const auto lagrange_third = View(in.lagrange_third);
65 const auto transcript_Pinfinity = View(in.transcript_base_infinity);
66 const auto transcript_Px_inverse = View(in.transcript_base_x_inverse);
67 const auto transcript_Py_inverse = View(in.transcript_base_y_inverse);
68 const auto transcript_add_x_equal = View(in.transcript_add_x_equal);
69 const auto transcript_add_y_equal = View(in.transcript_add_y_equal);
70 const auto transcript_add_lambda = View(in.transcript_add_lambda);
71 const auto transcript_msm_infinity = View(in.transcript_msm_infinity);
72
73 const auto is_not_first_row = -lagrange_first + FF(1);
74 const auto is_not_last_row = -lagrange_last + FF(1);
75 const auto is_not_first_or_last_row = (-lagrange_first - lagrange_last) + FF(1);
76 const auto is_not_infinity = -transcript_Pinfinity + FF(1);
77 const auto is_not_hiding_row = -lagrange_second + FF(1);
78
79 // Z1/Z2 zero checks: deg 2, length 3.
80 std::get<Base::Z1_ZERO_CHECK>(accumulator) += Acc3(z1 * (z1_zero * scaling_factor));
81 std::get<Base::Z2_ZERO_CHECK>(accumulator) += Acc3(z2 * (z2_zero * scaling_factor));
82
83 // Opcode well-formed: deg 1, length 2.
84 auto tmp = q_add + q_add;
85 tmp += q_mul;
86 tmp += tmp;
87 tmp += q_eq;
88 tmp += tmp;
89 tmp += q_reset_accumulator;
90 std::get<Base::OPCODE_WELL_FORMED>(accumulator) += Acc2((tmp - op) * scaling_factor);
91
92 // PC update: deg 4, length 5.
93 const auto pc_delta_short = pc - pc_shift; // length 2
94 const auto z1_active = -z1_zero + FF(1); // length 2
95 const auto z2_active = -z2_zero + FF(1); // length 2
96 const auto z_active_sum = z1_active + z2_active; // length 2
97 const auto num_muls_in_row = z_active_sum * is_not_infinity; // length 3
98 {
99 const auto first_term = Acc5((is_not_first_row * pc_delta_short) * scaling_factor);
100 const auto second_term = Acc5(is_not_first_row * q_mul) * Acc5(num_muls_in_row * scaling_factor);
101 std::get<Base::PC_UPDATE>(accumulator) += first_term - second_term;
102 }
103
104 // MSM_COUNT_ZERO_AT_TRANSITION: deg 6, length 7.
105 const auto msm_transition_check = q_mul * (-q_mul_shift + FF(1)); // length 3
106 {
107 const auto msm_count_total_acc7 = Acc7(msm_count) + Acc7(num_muls_in_row);
108 const auto check_a = Acc7(msm_count_zero_at_transition) * msm_count_total_acc7;
109 const auto inv_term = msm_count_total_acc7 * Acc7(msm_count_at_transition_inverse) - Acc7(FF(1));
110 const auto inactive = Acc7(-msm_count_zero_at_transition + FF(1));
111 const auto zero_check = check_a + inv_term * inactive;
113 Acc7(msm_transition_check * scaling_factor) * zero_check;
114 }
115
116 // MSM_TRANSITION: deg 3, length 4.
117 {
118 const auto not_zero_at_transition = Acc4(-msm_count_zero_at_transition + FF(1));
119 const auto outer = Acc4(msm_transition * scaling_factor) -
120 Acc4(msm_transition_check * scaling_factor) * not_zero_at_transition;
121 std::get<Base::MSM_TRANSITION>(accumulator) += outer;
122 }
123
124 // MSM_COUNT_ZERO_WHEN_NOT_MUL: deg 2, length 3.
125 std::get<Base::MSM_COUNT_ZERO_WHEN_NOT_MUL>(accumulator) += Acc3(((-q_mul + FF(1)) * msm_count) * scaling_factor);
126
127 // MSM_COUNT_INCREMENT_ACROSS_ROWS: deg 5, length 6.
128 const auto msm_count_delta = msm_count_shift - msm_count;
129 {
130 const auto outer_short = is_not_first_row * (-msm_transition + FF(1)); // length 3
131 const auto inner =
132 Acc6(msm_count_delta * scaling_factor) - Acc6(q_mul) * Acc6(num_muls_in_row * scaling_factor);
133 std::get<Base::MSM_COUNT_INCREMENT_ACROSS_ROWS>(accumulator) += Acc6(outer_short) * inner;
134 }
135
136 // OPCODE_EXCLUSION: deg 2, length 3.
137 {
138 const auto mul_other = q_add + q_eq + q_reset_accumulator;
139 const auto add_other = q_mul + q_eq + q_reset_accumulator;
140 const auto sum = q_mul * mul_other + q_add * add_other; // length 3
141 std::get<Base::OPCODE_EXCLUSION>(accumulator) += Acc3(sum * scaling_factor);
142 }
143
144 // EQ checks: deg 5, length 6.
145 const auto both_infinity_short = transcript_Pinfinity * is_accumulator_empty; // length 3
146 const auto not_pinf = -transcript_Pinfinity + FF(1); // length 2
147 const auto not_acc_empty = -is_accumulator_empty + FF(1); // length 2
148 const auto both_not_infinity_short = not_pinf * not_acc_empty; // length 3
149 const auto infinity_exclusion_short =
150 ((-both_infinity_short) - both_infinity_short) + (transcript_Pinfinity + is_accumulator_empty); // length 3
151 const auto q_eq_hiding_short = q_eq * is_not_hiding_row; // length 3
152 {
153 const auto eq_x_diff = transcript_Px - transcript_accumulator_x; // length 2
154 const auto inner_x = Acc6(eq_x_diff) * Acc6(both_not_infinity_short) + Acc6(infinity_exclusion_short);
155 std::get<Base::EQ_X_DIFF>(accumulator) += Acc6(q_eq_hiding_short * scaling_factor) * inner_x;
156 }
157 {
158 const auto eq_y_diff = transcript_Py - transcript_accumulator_y;
159 const auto inner_y = Acc6(eq_y_diff) * Acc6(both_not_infinity_short) + Acc6(infinity_exclusion_short);
160 std::get<Base::EQ_Y_DIFF>(accumulator) += Acc6(q_eq_hiding_short * scaling_factor) * inner_y;
161 }
162
163 // Boundary conditions: deg 2, length 3.
165 Acc3((lagrange_third * (-is_accumulator_empty + FF(1))) * scaling_factor);
167 Acc3((lagrange_third * msm_count + lagrange_last * pc) * scaling_factor);
168
169 // ON_CURVE_CHECK: deg 6, length 7.
170 {
171 const auto validate_on_curve = q_add + q_mul + q_eq; // length 2
172 const auto py_sq = transcript_Py.sqr(); // length 3
173 const auto px_sq = transcript_Px.sqr(); // length 3
174 const auto on_curve_check =
175 Acc7(py_sq) - Acc7(px_sq) * Acc7(transcript_Px) - Acc7(Base::get_curve_b()); // deg 3
176 const auto gating_short = is_not_infinity * is_not_hiding_row; // length 3
177 const auto outer = Acc7(validate_on_curve) * Acc7(gating_short * scaling_factor);
178 std::get<Base::ON_CURVE_CHECK>(accumulator) += outer * on_curve_check;
179 }
180
181 // Lambda relation / accumulator updates / offset generator / ADD_X/Y_EQUAL / ACC_EMPTY: shared block.
182 {
183 const auto is_double_short = transcript_add_x_equal * transcript_add_y_equal; // length 3
184 const auto is_add_short = -transcript_add_x_equal + FF(1); // length 2
185 const auto rhs_x = transcript_accumulator_x;
186 const auto rhs_y = transcript_accumulator_y;
187 const auto out_x = transcript_accumulator_x_shift;
188 const auto out_y = transcript_accumulator_y_shift;
189 const auto lambda = transcript_add_lambda;
190
191 const auto lhs_x_short = transcript_Px * q_add + transcript_msm_x * msm_transition; // length 3
192 const auto lhs_y_short = transcript_Py * q_add + transcript_msm_y * msm_transition; // length 3
193 const auto lhs_infinity_short =
194 transcript_Pinfinity * q_add + transcript_msm_infinity * msm_transition; // length 3
195 const auto rhs_infinity_short = is_accumulator_empty; // length 2
196 const auto neg_lhs_inf_plus_one_short = -lhs_infinity_short + FF(1); // length 3
197 const auto neg_rhs_inf_plus_one_short = -rhs_infinity_short + FF(1); // length 2
198
199 // These intermediates are shared across LAMBDA / ACC_X/Y / ACC_EMPTY (all length 8).
200 const auto result_is_lhs = Accumulator(rhs_infinity_short) * Accumulator(neg_lhs_inf_plus_one_short);
201 const auto result_is_rhs = Accumulator(neg_rhs_inf_plus_one_short) * Accumulator(lhs_infinity_short);
202 const auto result_infinity_from_inputs = Accumulator(lhs_infinity_short) * Accumulator(rhs_infinity_short);
203 const auto result_infinity_from_op_short =
204 transcript_add_x_equal * (-transcript_add_y_equal + FF(1)); // length 3
205 const auto result_is_infinity_short =
206 result_infinity_from_inputs + Accumulator(result_infinity_from_op_short); // deg 2
207 const auto any_add_is_active_short = q_add + msm_transition; // length 2
208
209 Accumulator transcript_lambda_relation(0);
210 // MSM lambda relation
211 {
212 Accumulator transcript_msm_lambda_relation(0);
213 const auto msm_x = transcript_msm_x;
214 const auto msm_y = transcript_msm_y;
215 {
216 const auto lambda_den = rhs_x - msm_x;
217 const auto lambda_num = rhs_y - msm_y;
218 const auto lambda_rel = Accumulator(lambda * lambda_den) - Accumulator(lambda_num);
219 transcript_msm_lambda_relation += lambda_rel * Accumulator(is_add_short);
220 }
221 {
222 const auto lambda_den = msm_y + msm_y;
223 const auto lambda_num_short = msm_x.sqr() * FF(3);
224 const auto lambda_rel = Accumulator(lambda * lambda_den) - Accumulator(lambda_num_short);
225 transcript_msm_lambda_relation += lambda_rel * Accumulator(is_double_short);
226 }
227 const auto valid_short = (-transcript_msm_infinity + FF(1)) * (-is_accumulator_empty + FF(1));
228 transcript_msm_lambda_relation *= Accumulator(valid_short);
229 {
230 const auto invalid_short =
231 result_infinity_from_op_short + (transcript_msm_infinity + is_accumulator_empty);
232 transcript_msm_lambda_relation += Accumulator(lambda) * Accumulator(invalid_short);
233 }
234 transcript_lambda_relation = transcript_msm_lambda_relation * Accumulator(msm_transition * scaling_factor);
235 }
236 // Base-point add lambda relation
237 {
238 Accumulator transcript_add_lambda_relation(0);
239 const auto add_x = transcript_Px;
240 const auto add_y = transcript_Py;
241 {
242 const auto lambda_den = rhs_x - add_x;
243 const auto lambda_num = rhs_y - add_y;
244 const auto lambda_rel = Accumulator(lambda * lambda_den) - Accumulator(lambda_num);
245 transcript_add_lambda_relation += lambda_rel * Accumulator(is_add_short);
246 }
247 {
248 const auto lambda_den = add_y + add_y;
249 const auto lambda_num_short = add_x.sqr() * FF(3);
250 const auto lambda_rel = Accumulator(lambda * lambda_den) - Accumulator(lambda_num_short);
251 transcript_add_lambda_relation += lambda_rel * Accumulator(is_double_short);
252 }
253 const auto valid_short = (-transcript_Pinfinity + FF(1)) * (-is_accumulator_empty + FF(1));
254 transcript_add_lambda_relation *= Accumulator(valid_short);
255 {
256 const auto invalid_short =
257 result_infinity_from_op_short + (transcript_Pinfinity + is_accumulator_empty);
258 transcript_add_lambda_relation += Accumulator(lambda) * Accumulator(invalid_short);
259 }
260 transcript_lambda_relation += transcript_add_lambda_relation * Accumulator(q_add * scaling_factor);
261 std::get<Base::LAMBDA_RELATION>(accumulator) += transcript_lambda_relation;
262 }
263
264 // ACCUMULATOR_X/Y_UPDATE — length 8.
265 const auto propagate_transcript_accumulator_short =
266 q_mul * (-msm_transition + FF(1)) + q_eq * (-q_reset_accumulator + FF(1)); // length 3
267 const auto opcode_is_zero_short_part_a = is_not_first_row * (-q_add + FF(1));
268 const auto opcode_is_zero_short_part_b = (-q_mul + FF(1)) * (-q_reset_accumulator + FF(1));
269 const auto opcode_is_zero_short_part_c = -q_eq + FF(1);
270 const auto opcode_is_zero_scaled = Accumulator(opcode_is_zero_short_part_a * scaling_factor) *
271 Accumulator(opcode_is_zero_short_part_b) *
272 Accumulator(opcode_is_zero_short_part_c); // deg 5
273 const auto any_add_is_active_scaled_acc = Accumulator(any_add_is_active_short * scaling_factor);
274 const auto propagate_transcript_accumulator_scaled = propagate_transcript_accumulator_short * scaling_factor;
275 {
276 const auto lambda_sqr = Accumulator(lambda.sqr());
277 const auto lhs_x_acc = Accumulator(lhs_x_short);
278 const auto lhs_y_acc = Accumulator(lhs_y_short);
279 const auto rhs_x_acc = Accumulator(rhs_x);
280 const auto rhs_y_acc = Accumulator(rhs_y);
281 auto x3 = lambda_sqr - lhs_x_acc - rhs_x_acc;
282 auto y3 = Accumulator(lambda) * (lhs_x_acc - x3) - lhs_y_acc;
283 x3 += result_is_lhs * (rhs_x_acc + lhs_x_acc + lhs_x_acc);
284 x3 += result_is_rhs * (lhs_x_acc + rhs_x_acc + rhs_x_acc);
285 x3 += result_is_infinity_short * (lhs_x_acc + rhs_x_acc);
286 y3 += result_is_lhs * (lhs_y_acc + lhs_y_acc);
287 y3 += result_is_rhs * (lhs_y_acc + rhs_y_acc);
288 y3 += result_is_infinity_short * lhs_y_acc;
289
290 const auto propagate_acc_x = Accumulator(propagate_transcript_accumulator_scaled) *
291 Accumulator(is_not_last_row * (out_x - transcript_accumulator_x));
292 const auto propagate_acc_y = Accumulator(propagate_transcript_accumulator_scaled) *
293 Accumulator(is_not_last_row * (out_y - transcript_accumulator_y));
294 auto add_point_x_relation = (x3 - Accumulator(out_x)) * any_add_is_active_scaled_acc + propagate_acc_x +
295 Accumulator(out_x * (q_reset_accumulator * scaling_factor)) +
296 Accumulator(out_x) * opcode_is_zero_scaled;
297 auto add_point_y_relation = (y3 - Accumulator(out_y)) * any_add_is_active_scaled_acc + propagate_acc_y +
298 Accumulator(out_y * (q_reset_accumulator * scaling_factor)) +
299 Accumulator(out_y) * opcode_is_zero_scaled;
300 std::get<Base::ACCUMULATOR_X_UPDATE>(accumulator) += add_point_x_relation;
301 std::get<Base::ACCUMULATOR_Y_UPDATE>(accumulator) += add_point_y_relation;
302 }
303
304 // The offset-generator subtraction and MSM-infinity subrelations (OFFSET_GENERATOR_X/Y, MSM_INFINITY_*) are
305 // gated entirely by `msm_transition` and live in ECCVMTranscriptMsmTransitionShortRelation so the prover can
306 // skip them when msm_transition == 0.
307
308 // ACCUMULATOR_EMPTY_UPDATE — length 8 (shares opcode_is_zero, result_is_infinity_short).
309 {
310 const auto accumulator_infinity_preserve =
311 Accumulator(propagate_transcript_accumulator_scaled) *
312 Accumulator(is_not_first_or_last_row * (is_accumulator_empty - is_accumulator_empty_shift));
313 const auto accumulator_infinity_q_reset =
314 Accumulator((q_reset_accumulator * (-is_accumulator_empty_shift + FF(1))) * scaling_factor);
315 const auto accumulator_infinity_from_add =
316 any_add_is_active_scaled_acc * (result_is_infinity_short - Accumulator(is_accumulator_empty_shift));
317 const auto accumulator_infinity_from_noop =
318 opcode_is_zero_scaled * Accumulator(-is_accumulator_empty_shift + FF(1));
319 const auto accumulator_infinity_relation =
320 accumulator_infinity_preserve +
321 (accumulator_infinity_q_reset + accumulator_infinity_from_add) * Accumulator(is_not_first_row) +
322 accumulator_infinity_from_noop;
323 std::get<Base::ACCUMULATOR_EMPTY_UPDATE>(accumulator) += accumulator_infinity_relation;
324 }
325
326 // ADD_X_EQUAL / ADD_Y_EQUAL: deg 5, length 6.
327 {
328 const auto x_diff = Acc6(lhs_x_short - rhs_x); // deg 2
329 const auto x_product =
330 Acc6(transcript_Px_inverse * (-transcript_add_x_equal + FF(1))) + Acc6(transcript_add_x_equal); // deg 2
331 const auto x_constant = transcript_add_x_equal - FF(1);
332 const auto x_relation =
333 (x_diff * x_product + Acc6(x_constant)) * Acc6(any_add_is_active_short * scaling_factor);
334 std::get<Base::ADD_X_EQUAL_CHECK>(accumulator) += x_relation;
335 }
336 {
337 const auto y_diff = Acc6(lhs_y_short - rhs_y);
338 const auto y_product =
339 Acc6(transcript_Py_inverse * (-transcript_add_y_equal + FF(1))) + Acc6(transcript_add_y_equal);
340 const auto y_constant = transcript_add_y_equal - FF(1);
341 const auto y_relation =
342 (y_diff * y_product + Acc6(y_constant)) * Acc6(any_add_is_active_short * scaling_factor);
343 std::get<Base::ADD_Y_EQUAL_CHECK>(accumulator) += y_relation;
344 }
345 }
346
347 // Hiding row constraints: deg 2, length 3.
348 std::get<Base::HIDING_ROW_EQ>(accumulator) += Acc3((lagrange_second * (-q_eq + FF(1))) * scaling_factor);
350 Acc3((lagrange_second * (-q_reset_accumulator + FF(1))) * scaling_factor);
351
352 // Infinity-flag consistency: deg 2, length 3.
353 std::get<Base::INFINITY_BASE_PX>(accumulator) += Acc3((transcript_Pinfinity * transcript_Px) * scaling_factor);
354 std::get<Base::INFINITY_BASE_PY>(accumulator) += Acc3((transcript_Pinfinity * transcript_Py) * scaling_factor);
355 std::get<Base::INFINITY_ACC_X>(accumulator) +=
356 Acc3((is_accumulator_empty * transcript_accumulator_x) * scaling_factor);
357 std::get<Base::INFINITY_ACC_Y>(accumulator) +=
358 Acc3((is_accumulator_empty * transcript_accumulator_y) * scaling_factor);
359
360 // ACCUMULATOR_NOT_EMPTY_INIT: deg 2, length 3.
362 Acc3((lagrange_first * transcript_accumulator_not_empty) * scaling_factor);
363}
364
365} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
typename Accumulator::CoefficientAccumulator ECCVMShortMonomialView
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13