Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_wnaf_relation_impl.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Raju], commit: 2a49eb6 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8
9namespace bb {
10
44template <typename FF>
45template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
46void ECCVMWnafRelationImpl<FF>::accumulate(ContainerOverSubrelations& accumulator,
47 const AllEntities& in,
48 const Parameters& /*unused*/,
49 const FF& scaling_factor)
50{
52 using View = typename Accumulator::View;
53 auto lagrange_first = View(in.lagrange_first);
54 auto scalar_sum = View(in.precompute_scalar_sum);
55 auto scalar_sum_shift = View(in.precompute_scalar_sum_shift);
56 auto q_transition = View(in.precompute_point_transition);
57 auto round = View(in.precompute_round);
58 auto round_shift = View(in.precompute_round_shift);
59 auto pc = View(in.precompute_pc); // note that this is a _point-counter_.
60 auto pc_shift = View(in.precompute_pc_shift);
61 // precompute_select is a boolean column that is 0 at the initial row and 1 at all subsequent active rows in the
62 // precompute table. We only evaluate the ecc_wnaf_relation and the ecc_point_table_relation if
63 // `precompute_select=1`. As a reminder, this latter is 0 at the initial row and then 1 at the rest of the (active)
64 // rows of the Precomputed table. The fact that `precompute_select` is correctly computed is mediated by the set
65 // relation.
66 auto precompute_select = View(in.precompute_select);
67
68 auto precompute_select_shift = View(in.precompute_select_shift);
69
70 const auto& precompute_skew = View(in.precompute_skew);
71
72 const std::array<View, 8> slices{
73 View(in.precompute_s1hi), View(in.precompute_s1lo), View(in.precompute_s2hi), View(in.precompute_s2lo),
74 View(in.precompute_s3hi), View(in.precompute_s3lo), View(in.precompute_s4hi), View(in.precompute_s4lo),
75 };
76
77 const auto range_constraint_slice_to_2_bits = [&scaling_factor](const View& s, auto& acc) {
78 acc += ((s - 1).sqr() - 1) * ((s - 2).sqr() - 1) * scaling_factor;
79 };
80
81 // given two 2-bit numbers `s0, `s1`, convert to a wNAF digit (in {-15, -13, ..., 13, 15}) via the formula:
82 // `2(4s0 + s1) - 15`. (Here, `4s0 + s1` represents the 4-bit number corresponding to the concatenation of `s0` and
83 // `s1`.)
84 const auto convert_to_wnaf = [](const View& s0, const View& s1) {
85 auto t = s0 + s0;
86 t += t;
87 t += s1;
88 auto naf = t + t - 15;
89 return naf;
90 };
91
92 const auto scaled_transition = q_transition * scaling_factor;
93 const auto scaled_transition_is_zero =
94 -scaled_transition + scaling_factor; // `scaling_factor * (1 - q_transition)`, i.e., is the scaling_factor if we
95 // are _not_ at a transition, else 0.
96
97 const auto scaled_lagrange_first = scaling_factor * lagrange_first; // for edge-case handling
103 range_constraint_slice_to_2_bits(slices[0], std::get<0>(accumulator));
104 range_constraint_slice_to_2_bits(slices[1], std::get<1>(accumulator));
105 range_constraint_slice_to_2_bits(slices[2], std::get<2>(accumulator));
106 range_constraint_slice_to_2_bits(slices[3], std::get<3>(accumulator));
107 range_constraint_slice_to_2_bits(slices[4], std::get<4>(accumulator));
108 range_constraint_slice_to_2_bits(slices[5], std::get<5>(accumulator));
109 range_constraint_slice_to_2_bits(slices[6], std::get<6>(accumulator));
110 range_constraint_slice_to_2_bits(slices[7], std::get<7>(accumulator));
111
120 const auto s1_shift = View(in.precompute_s1hi_shift);
121 const auto s1_shift_msb_set = (s1_shift - 2) * (s1_shift - 3);
122 const auto scaled_transition_plus_lagrange_first = scaled_transition + scaled_lagrange_first;
123 // away from row zero, add `scaled_transition * precompute_select_shift * s1_shift_msb_set`. however,
124 // `q_transition[0] == 0`, so this constraint will not turn on at the 0th row unless we add
125 // `scaled_lagrange_first`.
126 std::get<20>(accumulator) += scaled_transition_plus_lagrange_first * precompute_select_shift * s1_shift_msb_set;
133 const auto w0 = convert_to_wnaf(slices[0], slices[1]);
134 const auto w1 = convert_to_wnaf(slices[2], slices[3]);
135 const auto w2 = convert_to_wnaf(slices[4], slices[5]);
136 const auto w3 = convert_to_wnaf(slices[6], slices[7]);
137
147 auto row_slice = w0; // row_slice will eventually contain the truncated scalar corresponding to the current row,
148 // which is 2^12 * w_0 + 2^8 * w_1 + 2^4 * w_2 + w_3. (If one just looks at the wNAF digits in
149 // this row, this is the resulting odd number. Note that it is not necessarily positive.)
150 row_slice += row_slice;
151 row_slice += row_slice;
152 row_slice += row_slice;
153 row_slice += row_slice;
154 row_slice += w1;
155 row_slice += row_slice;
156 row_slice += row_slice;
157 row_slice += row_slice;
158 row_slice += row_slice;
159 row_slice += w2;
160 row_slice += row_slice;
161 row_slice += row_slice;
162 row_slice += row_slice;
163 row_slice += row_slice;
164 row_slice += w3;
165 auto sum_delta = scalar_sum * FF(1ULL << 16) + row_slice;
166 const auto check_sum = scalar_sum_shift - sum_delta;
167 std::get<8>(accumulator) += precompute_select * check_sum * scaled_transition_is_zero;
168
212 // We combine two checks into a single relation
213 // q_transition * (round - 7) + (-q_transition + 1) * (round_shift - round - 1)
214 // => q_transition * (round - 7 - round_shift + round + 1) + (round_shift - round - 1)
215 // => q_transition * (2 * round - round_shift - 6) + (round_shift - round - 1)
216 const auto round_check = round_shift - round - 1;
217 // This selector is 1 at row 0 (via lagrange_first) and at transition rows where precompute_select == 1.
218 // It's used to constrain shifted values (like round_shift, scalar_sum_shift) that need to be checked
219 // both at the first active row AND at subsequent transitions between scalars.
220 const auto precompute_select_transition_plus_lagrange_first =
221 precompute_select * scaled_transition + scaled_lagrange_first;
222 std::get<9>(accumulator) +=
223 precompute_select * (scaled_transition * (round - round_check - 7) + scaling_factor * round_check);
224 // At a transition (or at row 0 via lagrange_first), the next round must be 0.
225 std::get<10>(accumulator) += precompute_select_transition_plus_lagrange_first * round_shift;
226
234 std::get<11>(accumulator) += precompute_select_transition_plus_lagrange_first * scalar_sum_shift;
235 // (2, 3 combined): q_transition * (pc - pc_shift - 1) + (-q_transition + 1) * (pc_shift - pc)
236 // => q_transition * (-2 * (pc_shift - pc) - 1) + (pc_shift - pc)
237 const auto pc_delta = pc_shift - pc;
238 std::get<12>(accumulator) +=
239 precompute_select * (scaled_transition * ((-pc_delta - pc_delta - 1)) + pc_delta * scaling_factor);
240
250 std::get<13>(accumulator) += precompute_select * (precompute_skew * (precompute_skew - 7)) * scaling_factor;
251
252 // Set slices (a.k.a. compressed digits), pc, and round all to zero when `precompute_select == 0`.
253 // (this is for one of the multiset equality checks.)
254 const auto precompute_select_zero = (-precompute_select + 1) * scaling_factor;
255 std::get<14>(accumulator) += precompute_select_zero * (w0 + 15);
256 std::get<15>(accumulator) += precompute_select_zero * (w1 + 15);
257 std::get<16>(accumulator) += precompute_select_zero * (w2 + 15);
258 std::get<17>(accumulator) += precompute_select_zero * (w3 + 15);
259
260 std::get<18>(accumulator) += precompute_select_zero * round;
261 std::get<19>(accumulator) += precompute_select_zero * pc;
262
263 // Note(@zac-williamson #2226)
264 // if precompute_select = 0, validate pc, round, slice values are all zero
265 // If we do this we can reduce the degree of the set equivalence relations
266 // (currently when checking pc/round/wnaf tuples from WNAF columns match those from MSM columns,
267 // we conditionally include tuples depending on if precompute_select = 1 (for WNAF columns) or if q_add1/2/3/4 = 1
268 // (for MSM columns).
269 // If we KNOW that the wnaf tuple values are 0 when precompute_select = 0, we can remove the conditional checks in
270 // the set equivalence relation
271}
272} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:22
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &, const FF &scaling_factor)
ECCVMWnafRelationImpl evaluates relations that convert scalar multipliers into 4-bit WNAF slices.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13