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 // We must constrain `precompute_select` to be of the correct shape: 0 1 1 ... 1 0 ...0. In other words, after the
169 // first row, it is monotonically non-decreasing. In other words, a malicious prover cannot inject the value '0' in
170 // the middle.
171 const auto scaled_lagrange_first_minus_one =
172 scaled_lagrange_first - scaling_factor; // (if not at the first row, is -1, else 0) * scaling_factor
173 const auto precompute_select_check = precompute_select_shift * (precompute_select - 1);
174 std::get<22>(accumulator) += scaled_lagrange_first_minus_one * precompute_select_check;
218 // We combine two checks into a single relation
219 // q_transition * (round - 7) + (-q_transition + 1) * (round_shift - round - 1)
220 // => q_transition * (round - 7 - round_shift + round + 1) + (round_shift - round - 1)
221 // => q_transition * (2 * round - round_shift - 6) + (round_shift - round - 1)
222 const auto round_check = round_shift - round - 1;
223 // This selector is 1 at row 0 (via lagrange_first) and at transition rows where precompute_select == 1.
224 // It's used to constrain shifted values (like round_shift, scalar_sum_shift) that need to be checked
225 // both at the first active row AND at subsequent transitions between scalars.
226 const auto precompute_select_transition_plus_lagrange_first =
227 precompute_select * scaled_transition + scaled_lagrange_first;
228 std::get<9>(accumulator) +=
229 precompute_select * (scaled_transition * (round - round_check - 7) + scaling_factor * round_check);
230 // At a transition (or at row 0 via lagrange_first), the next round must be 0.
231 std::get<10>(accumulator) += precompute_select_transition_plus_lagrange_first * round_shift;
232
240 std::get<11>(accumulator) += precompute_select_transition_plus_lagrange_first * scalar_sum_shift;
241 // (2, 3 combined): q_transition * (pc - pc_shift - 1) + (-q_transition + 1) * (pc_shift - pc)
242 // => q_transition * (-2 * (pc_shift - pc) - 1) + (pc_shift - pc)
243 const auto pc_delta = pc_shift - pc;
244 std::get<12>(accumulator) +=
245 precompute_select * (scaled_transition * ((-pc_delta - pc_delta - 1)) + pc_delta * scaling_factor);
246
256 std::get<13>(accumulator) += precompute_select * (precompute_skew * (precompute_skew - 7)) * scaling_factor;
257
258 // Set slices (a.k.a. compressed digits), pc, and round all to zero when `precompute_select == 0`.
259 // (this is for one of the multiset equality checks.) Defensively, we also set precompute_point_transition to 0 when
260 // precompute_select == 0.
261 const auto precompute_select_zero = (-precompute_select + 1) * scaling_factor;
262 std::get<14>(accumulator) += precompute_select_zero * (w0 + 15);
263 std::get<15>(accumulator) += precompute_select_zero * (w1 + 15);
264 std::get<16>(accumulator) += precompute_select_zero * (w2 + 15);
265 std::get<17>(accumulator) += precompute_select_zero * (w3 + 15);
266
267 std::get<18>(accumulator) += precompute_select_zero * round;
268 std::get<19>(accumulator) += precompute_select_zero * pc;
269 std::get<21>(accumulator) += precompute_select_zero * q_transition;
270}
271} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
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