Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_shiftable_init_relation_impl.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8
9namespace bb {
10
11template <typename FF>
12template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
13void ECCVMShiftableInitRelationImpl<FF>::accumulate(ContainerOverSubrelations& accumulator,
14 const AllEntities& in,
15 const Parameters& /*unused*/,
16 const FF& scaling_factor)
17{
19
20 const auto accumulate_init = [&]<size_t subrelation_idx>(const auto& entity) {
21 if constexpr (requires { typename Accumulator::CoefficientAccumulator; }) {
22 using View = typename Accumulator::CoefficientAccumulator;
23 const auto scaled_lagrange_first = View(in.lagrange_first) * scaling_factor;
24 std::get<subrelation_idx>(accumulator) += Accumulator(scaled_lagrange_first * View(entity));
25 } else {
26 using View = typename Accumulator::View;
27 const auto scaled_lagrange_first = View(in.lagrange_first) * scaling_factor;
28 std::get<subrelation_idx>(accumulator) += scaled_lagrange_first * View(entity);
29 }
30 };
31
32 // ---- Load-bearing ----
33
34 // Grand product initialization. The set relation's GRAND_PRODUCT subrelation evaluates
35 // (z_perm + lagrange_first) * num - (z_perm_shift + lagrange_last) * den
36 // and relies on z_perm at the lagrange_first row being 0, so that the bracketed sum
37 // starts at 1. Previously lived as Z_PERM_INIT inside ECCVMSetRelation; centralized
38 // here so every direct `lagrange_first · col = 0` constraint sits in one place.
39 accumulate_init.template operator()<Z_PERM_INIT>(in.z_perm);
40
41 // Anchors the transcript accumulator "empty" flag to true at the lagrange_first row.
42 // Cascades through `is_accumulator_empty · transcript_accumulator_{x,y} = 0` in
43 // ECCVMTranscriptRelation to also pin both accumulator coordinates to 0 there.
44 // Previously lived as ACCUMULATOR_NOT_EMPTY_INIT inside ECCVMTranscriptRelation.
45 accumulate_init.template operator()<TRANSCRIPT_ACCUMULATOR_NOT_EMPTY_INIT>(in.transcript_accumulator_not_empty);
46
47 // Without this, a malicious prover can set `precompute_select = 1` together with
48 // `q_transition = 1` at the lagrange_first row to inject a phantom 1-row scalar whose
49 // `precompute_scalar_sum` (an unbounded field element) is then communicated to the
50 // transcript-side `z1` via the second-term multiset, breaking the [0, 2^128) bound
51 // that `FIRST_SLICE_POSITIVE + SCALAR_SUM_CHECK` are supposed to enforce on `z1`. See
52 // ecc_wnaf_relation_impl.hpp for the chain.
53 //
54 // Once pinned, the existing `INACTIVE_*` constraints in ECCVMWnafRelation cascade:
55 // they force `precompute_pc`, `precompute_round`, `q_transition`, and
56 // `precompute_s1hi` (with the range constraints) all to 0 at lagrange_first.
57 accumulate_init.template operator()<PRECOMPUTE_SELECT_INIT>(in.precompute_select);
58
59 // Without this, a malicious prover can set `transcript_mul = 1` at lagrange_first to
60 // inject an extra second-term denominator factor into the set relation (see
61 // `point_table_init_write` in ecc_set_relation_impl.hpp). The fingerprint is
62 // `(transcript_pc, transcript_Px, transcript_Py, z1|z2)`, all of which the prover
63 // controls at the lagrange_first row. No other relation pins `transcript_mul` there:
64 // `BOOL_Q_MUL` only ranges it to {0,1}, `PC_UPDATE` is gated off by
65 // `is_not_first_row = 0`, and `MSM_COUNT_ZERO_WHEN_NOT_MUL` only constrains
66 // `msm_count` from `transcript_mul = 0`, not the other direction.
67 accumulate_init.template operator()<TRANSCRIPT_MUL_INIT>(in.transcript_mul);
68
69 // Without this, the malicious `transcript_mul = 1` fingerprint above can use an
70 // attacker-chosen `transcript_pc` at lagrange_first. The PC_UPDATE comment in
71 // ecc_transcript_relation_impl.hpp explicitly says "the value of `pc` in the first
72 // row is 0 because `pc` is shiftable" — but the only constraint relying on that
73 // statement (PC_UPDATE) is gated by `is_not_first_row`, so it does not enforce it.
74 // The corresponding BOUNDARY_MSM_COUNT_AND_PC constraint pins `transcript_pc` at the
75 // *last* row (via `lagrange_last`), not at lagrange_first.
76 accumulate_init.template operator()<TRANSCRIPT_PC_INIT>(in.transcript_pc);
77
78 // ---- Defense-in-depth ----
79 //
80 // The following columns have witness values at the lagrange_first row that are not
81 // currently read by any firing constraint (their reads are gated off by
82 // `precompute_select = 0`, `q_*` selectors = 0, `is_not_first_row = 0`, or by
83 // `(1 - lagrange_first)` factors). We pin them here as an invariant rather than
84 // relying on the absence of a read, so that future relation changes cannot silently
85 // turn a now-unread column into a read at lagrange_first.
86
87 // precompute_scalar_sum: only read by SCALAR_SUM_CHECK (gated by `precompute_select`)
88 // and the second-term numerator (gated by `precompute_point_transition`), both 0 at
89 // lagrange_first once PRECOMPUTE_SELECT_INIT fires.
90 accumulate_init.template operator()<PRECOMPUTE_SCALAR_SUM_INIT>(in.precompute_scalar_sum);
91
92 // precompute_dx, dy, tx, ty: only read by ECCVMPointTableRelation (gated by
93 // `precompute_select`) and the second-term numerator (gated by `q_transition`).
94 accumulate_init.template operator()<PRECOMPUTE_DX_INIT>(in.precompute_dx);
95 accumulate_init.template operator()<PRECOMPUTE_DY_INIT>(in.precompute_dy);
96 accumulate_init.template operator()<PRECOMPUTE_TX_INIT>(in.precompute_tx);
97 accumulate_init.template operator()<PRECOMPUTE_TY_INIT>(in.precompute_ty);
98
99 // msm_transition: an honest builder writes 0 at lagrange_first. The third-term
100 // multiset emission gated by `msm_transition_shift` in ECCVMSetRelation is
101 // explicitly multiplied by `(1 - lagrange_first)`, so a malicious `msm_transition`
102 // value there does not perturb the third-term multiset. Pin as DiD.
103 accumulate_init.template operator()<MSM_TRANSITION_INIT>(in.msm_transition);
104
105 // msm_add / msm_double / msm_skew: gate the MSM ADD/DOUBLE/SKEW subrelations. At the
106 // lagrange_first row (honest), all three are 0 and the MSM relations are inert. A
107 // malicious flip would activate the relations, but their multiset emissions would
108 // have no matching numerator (precompute side is gated off by PRECOMPUTE_SELECT_INIT).
109 // Pin as DiD.
110 accumulate_init.template operator()<MSM_ADD_INIT>(in.msm_add);
111 accumulate_init.template operator()<MSM_DOUBLE_INIT>(in.msm_double);
112 accumulate_init.template operator()<MSM_SKEW_INIT>(in.msm_skew);
113
114 // msm_accumulator_x, msm_accumulator_y: read by ADD/DOUBLE/SKEW (gated by their
115 // selectors) and by IDLE_ROW_PRESERVES_ACC (gated by `(1 - lagrange_first)`). The
116 // accumulator chain at the next row starts fresh via `first_add(offset_generator)`
117 // anyway.
118 accumulate_init.template operator()<MSM_ACCUMULATOR_X_INIT>(in.msm_accumulator_x);
119 accumulate_init.template operator()<MSM_ACCUMULATOR_Y_INIT>(in.msm_accumulator_y);
120
121 // msm_count, msm_round: read by various MSM subrelations which are all either gated
122 // by `q_add + q_double + q_skew` (= 0 at lagrange_first once the three pins above
123 // fire) or by `is_not_first_row = 0`.
124 accumulate_init.template operator()<MSM_COUNT_INIT>(in.msm_count);
125 accumulate_init.template operator()<MSM_ROUND_INIT>(in.msm_round);
126
127 // msm_add1: ADD1_DECOMPOSITION says `msm_add1 = q_add + q_skew`. Once both are
128 // pinned to 0 at lagrange_first, this is redundant — included for explicitness.
129 accumulate_init.template operator()<MSM_ADD1_INIT>(in.msm_add1);
130
131 // msm_pc: read by MSM_TRANSITION_PC (gated by `is_not_first_row`), the first-term
132 // multiset denominator (gated by `add_i = 0` at lagrange_first), and the third-term
133 // emission (explicitly gated by `(1 - lagrange_first)`). Pin as DiD.
134 accumulate_init.template operator()<MSM_PC_INIT>(in.msm_pc);
135
136 // transcript_msm_count: pinned by MSM_COUNT_ZERO_WHEN_NOT_MUL (in
137 // ECCVMTranscriptRelation) once TRANSCRIPT_MUL_INIT fires. Included here to make the
138 // invariant independent of that cascade.
139 accumulate_init.template operator()<TRANSCRIPT_MSM_COUNT_INIT>(in.transcript_msm_count);
140}
141
142} // namespace bb
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &, const FF &scaling_factor)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13