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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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
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. We only evaluate the ecc_wnaf_relation and the ecc_point_table_relation if
62 // `precompute_select=1`
63 auto precompute_select = View(in.precompute_select);
64 auto precompute_select_shift = View(in.precompute_select_shift);
65
66 const auto& precompute_skew = View(in.precompute_skew);
67
68 const std::array<View, 8> slices{
69 View(in.precompute_s1hi), View(in.precompute_s1lo), View(in.precompute_s2hi), View(in.precompute_s2lo),
70 View(in.precompute_s3hi), View(in.precompute_s3lo), View(in.precompute_s4hi), View(in.precompute_s4lo),
71 };
72
73 const auto range_constraint_slice_to_2_bits = [&scaling_factor](const View& s, auto& acc) {
74 acc += ((s - 1).sqr() - 1) * ((s - 2).sqr() - 1) * scaling_factor;
75 };
76
77 // given two 2-bit numbers `s0, `s1`, convert to a wNAF digit (in {-15, -13, ..., 13, 15}) via the formula:
78 // `2(4s0 + s1) - 15`. (Here, `4s0 + s1` represents the 4-bit number corresponding to the concatenation of `s0` and
79 // `s1`.)
80 const auto convert_to_wnaf = [](const View& s0, const View& s1) {
81 auto t = s0 + s0;
82 t += t;
83 t += s1;
84 auto naf = t + t - 15;
85 return naf;
86 };
87
88 const auto scaled_transition = q_transition * scaling_factor;
89 const auto scaled_transition_is_zero =
90 -scaled_transition + scaling_factor; // `scaling_factor * (1 - q_transition)`, i.e., is the scaling_factor if we
91 // are _not_ at a transition, else 0.
97 range_constraint_slice_to_2_bits(slices[0], std::get<0>(accumulator));
98 range_constraint_slice_to_2_bits(slices[1], std::get<1>(accumulator));
99 range_constraint_slice_to_2_bits(slices[2], std::get<2>(accumulator));
100 range_constraint_slice_to_2_bits(slices[3], std::get<3>(accumulator));
101 range_constraint_slice_to_2_bits(slices[4], std::get<4>(accumulator));
102 range_constraint_slice_to_2_bits(slices[5], std::get<5>(accumulator));
103 range_constraint_slice_to_2_bits(slices[6], std::get<6>(accumulator));
104 range_constraint_slice_to_2_bits(slices[7], std::get<7>(accumulator));
105
114 const auto s1_shift = View(in.precompute_s1hi_shift);
115 const auto s1_shift_msb_set = (s1_shift - 2) * (s1_shift - 3);
116 std::get<20>(accumulator) += scaled_transition * precompute_select_shift * s1_shift_msb_set;
117
124 const auto w0 = convert_to_wnaf(slices[0], slices[1]);
125 const auto w1 = convert_to_wnaf(slices[2], slices[3]);
126 const auto w2 = convert_to_wnaf(slices[4], slices[5]);
127 const auto w3 = convert_to_wnaf(slices[6], slices[7]);
128
138 auto row_slice = w0; // row_slice will eventually contain the truncated scalar corresponding to the current row,
139 // 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
140 // this row, this is the resulting odd number. Note that it is not necessarily positive.)
141 row_slice += row_slice;
142 row_slice += row_slice;
143 row_slice += row_slice;
144 row_slice += row_slice;
145 row_slice += w1;
146 row_slice += row_slice;
147 row_slice += row_slice;
148 row_slice += row_slice;
149 row_slice += row_slice;
150 row_slice += w2;
151 row_slice += row_slice;
152 row_slice += row_slice;
153 row_slice += row_slice;
154 row_slice += row_slice;
155 row_slice += w3;
156 auto sum_delta = scalar_sum * FF(1ULL << 16) + row_slice;
157 const auto check_sum = scalar_sum_shift - sum_delta;
158 std::get<8>(accumulator) += precompute_select * check_sum * scaled_transition_is_zero;
159
203 // We combine two checks into a single relation
204 // q_transition * (round - 7) + (-q_transition + 1) * (round_shift - round - 1)
205 // => q_transition * (round - 7 - round_shift + round + 1) + (round_shift - round - 1)
206 // => q_transition * (2 * round - round_shift - 6) + (round_shift - round - 1)
207 const auto round_check = round_shift - round - 1;
208 std::get<9>(accumulator) +=
209 precompute_select * (scaled_transition * (round - round_check - 7) + scaling_factor * round_check);
210 std::get<10>(accumulator) +=
211 precompute_select * scaled_transition * round_shift; // at a transition, next round == 0
212
220 std::get<11>(accumulator) += precompute_select * scaled_transition * scalar_sum_shift;
221 // (2, 3 combined): q_transition * (pc - pc_shift - 1) + (-q_transition + 1) * (pc_shift - pc)
222 // => q_transition * (-2 * (pc_shift - pc) - 1) + (pc_shift - pc)
223 const auto pc_delta = pc_shift - pc;
224 std::get<12>(accumulator) +=
225 precompute_select * (scaled_transition * ((-pc_delta - pc_delta - 1)) + pc_delta * scaling_factor);
226
236 std::get<13>(accumulator) += precompute_select * (precompute_skew * (precompute_skew - 7)) * scaling_factor;
237
238 // Set slices (a.k.a. compressed digits), pc, and round all to zero when `precompute_select == 0`.
239 // (this is for one of the multiset equality checks.)
240 const auto precompute_select_zero = (-precompute_select + 1) * scaling_factor;
241 std::get<14>(accumulator) += precompute_select_zero * (w0 + 15);
242 std::get<15>(accumulator) += precompute_select_zero * (w1 + 15);
243 std::get<16>(accumulator) += precompute_select_zero * (w2 + 15);
244 std::get<17>(accumulator) += precompute_select_zero * (w3 + 15);
245
246 std::get<18>(accumulator) += precompute_select_zero * round;
247 std::get<19>(accumulator) += precompute_select_zero * pc;
248
249 // Note(@zac-williamson #2226)
250 // if precompute_select = 0, validate pc, round, slice values are all zero
251 // If we do this we can reduce the degree of the set equivalence relations
252 // (currently when checking pc/round/wnaf tuples from WNAF columns match those from MSM columns,
253 // we conditionally include tuples depending on if precompute_select = 1 (for WNAF columns) or if q_add1/2/3/4 = 1
254 // (for MSM columns).
255 // If we KNOW that the wnaf tuple values are 0 when precompute_select = 0, we can remove the conditional checks in
256 // the set equivalence relation
257}
258} // namespace bb
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.
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13