Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup_tables.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
7#pragma once
12
14
31template <typename C, class Fq, class Fr, class G>
32template <size_t num_elements>
35{
41
42 for (size_t i = 0; i < num_elements; ++i) {
43 limb_max[0] = std::max(limb_max[0], rom_data[i]._x.binary_basis_limbs[0].maximum_value);
44 limb_max[1] = std::max(limb_max[1], rom_data[i]._x.binary_basis_limbs[1].maximum_value);
45 limb_max[2] = std::max(limb_max[2], rom_data[i]._x.binary_basis_limbs[2].maximum_value);
46 limb_max[3] = std::max(limb_max[3], rom_data[i]._x.binary_basis_limbs[3].maximum_value);
47 limb_max[4] = std::max(limb_max[4], rom_data[i]._y.binary_basis_limbs[0].maximum_value);
48 limb_max[5] = std::max(limb_max[5], rom_data[i]._y.binary_basis_limbs[1].maximum_value);
49 limb_max[6] = std::max(limb_max[6], rom_data[i]._y.binary_basis_limbs[2].maximum_value);
50 limb_max[7] = std::max(limb_max[7], rom_data[i]._y.binary_basis_limbs[3].maximum_value);
51
52 x_lo_limbs.emplace_back(std::array<field_ct, 2>{ rom_data[i]._x.binary_basis_limbs[0].element,
53 rom_data[i]._x.binary_basis_limbs[1].element });
54 x_hi_limbs.emplace_back(std::array<field_ct, 2>{ rom_data[i]._x.binary_basis_limbs[2].element,
55 rom_data[i]._x.binary_basis_limbs[3].element });
56 y_lo_limbs.emplace_back(std::array<field_ct, 2>{ rom_data[i]._y.binary_basis_limbs[0].element,
57 rom_data[i]._y.binary_basis_limbs[1].element });
58 y_hi_limbs.emplace_back(std::array<field_ct, 2>{ rom_data[i]._y.binary_basis_limbs[2].element,
59 rom_data[i]._y.binary_basis_limbs[3].element });
60 prime_limbs.emplace_back(
61 std::array<field_ct, 2>{ rom_data[i]._x.prime_basis_limb, rom_data[i]._y.prime_basis_limb });
62 }
63 std::array<twin_rom_table<C>, Fq::NUM_LIMBS + 1> output_tables;
64 output_tables[0] = twin_rom_table<C>(x_lo_limbs);
65 output_tables[1] = twin_rom_table<C>(x_hi_limbs);
66 output_tables[2] = twin_rom_table<C>(y_lo_limbs);
67 output_tables[3] = twin_rom_table<C>(y_hi_limbs);
68 output_tables[4] = twin_rom_table<C>(prime_limbs);
69 return output_tables;
70}
71
72template <typename C, class Fq, class Fr, class G>
73template <size_t>
75 const std::array<twin_rom_table<C>, Fq::NUM_LIMBS + 1>& tables,
76 const field_ct& index,
78{
79 const auto xlo = tables[0][index];
80 const auto xhi = tables[1][index];
81 const auto ylo = tables[2][index];
82 const auto yhi = tables[3][index];
83 const auto xyprime = tables[4][index];
84
85 // We assign maximum_value of each limb here, so we can use the unsafe API from element construction
86 Fq x_fq = Fq::unsafe_construct_from_limbs(xlo[0], xlo[1], xhi[0], xhi[1], xyprime[0]);
87 Fq y_fq = Fq::unsafe_construct_from_limbs(ylo[0], ylo[1], yhi[0], yhi[1], xyprime[1]);
88 x_fq.binary_basis_limbs[0].maximum_value = limb_max[0];
89 x_fq.binary_basis_limbs[1].maximum_value = limb_max[1];
90 x_fq.binary_basis_limbs[2].maximum_value = limb_max[2];
91 x_fq.binary_basis_limbs[3].maximum_value = limb_max[3];
92 y_fq.binary_basis_limbs[0].maximum_value = limb_max[4];
93 y_fq.binary_basis_limbs[1].maximum_value = limb_max[5];
94 y_fq.binary_basis_limbs[2].maximum_value = limb_max[6];
95 y_fq.binary_basis_limbs[3].maximum_value = limb_max[7];
96
97 // ROM table points are precomputed and known to be valid, skip curve check
98 const auto output = element(x_fq, y_fq, /*assert_on_curve=*/false);
99 return output;
100}
101
102template <typename C, class Fq, class Fr, class G>
104{
105 element d2 = input.dbl();
106
107 element_table[8] = input;
108 for (size_t i = 9; i < 16; ++i) {
109 element_table[i] = element_table[i - 1] + d2;
110 }
111 for (size_t i = 0; i < 8; ++i) {
112 element_table[i] = (-element_table[15 - i]);
113 }
114
115 coordinates = create_group_element_rom_tables<16>(element_table, limb_max);
116}
117
118template <typename C, class Fq, class Fr, class G>
120{
121 return read_group_element_rom_tables<16>(coordinates, index, limb_max);
122}
123
124template <class C, class Fq, class Fr, class G>
126{
127 const auto get_plookup_tags = [this]() {
128 switch (curve_type) {
131 use_endomorphism ? MultiTableId::SECP256K1_XLO_ENDO : MultiTableId::SECP256K1_XLO,
132 use_endomorphism ? MultiTableId::SECP256K1_XHI_ENDO : MultiTableId::SECP256K1_XHI,
133 MultiTableId::SECP256K1_YLO,
134 MultiTableId::SECP256K1_YHI,
135 use_endomorphism ? MultiTableId::SECP256K1_XYPRIME_ENDO : MultiTableId::SECP256K1_XYPRIME,
136 };
137 }
138 default: {
139 throw_or_abort("eight_bit_fixed_base_table only supports SECP256K1 curve type");
140 }
141 }
142 };
143
144 const auto tags = get_plookup_tags();
145
146 const auto xlo = plookup_read<C>::read_pair_from_table(tags[0], index);
147 const auto xhi = plookup_read<C>::read_pair_from_table(tags[1], index);
148 const auto ylo = plookup_read<C>::read_pair_from_table(tags[2], index);
149 const auto yhi = plookup_read<C>::read_pair_from_table(tags[3], index);
150 const auto xyprime = plookup_read<C>::read_pair_from_table(tags[4], index);
151
152 // All the elements are precomputed constants so they are completely reduced, so the default maximum limb values are
153 // appropriate
154 Fq x = Fq::unsafe_construct_from_limbs(xlo.first, xlo.second, xhi.first, xhi.second, xyprime.first);
155 Fq y = Fq::unsafe_construct_from_limbs(ylo.first, ylo.second, yhi.first, yhi.second, xyprime.second);
156
157 if (use_endomorphism) {
158 y = -y;
159 }
160
161 // Points from precomputed tables are known to be on the curve
162 return element(x, y, /*assert_on_curve=*/false);
163}
164
165template <typename C, class Fq, class Fr, class G>
170
174template <typename C, class Fq, class Fr, class G>
175template <size_t length>
177{
178 static_assert(length <= 6, "lookup_table_plookup only supports up to 6 input elements");
179
180 if constexpr (length == 2) {
181 auto [A0, A1] = inputs[1].checked_unconditional_add_sub(inputs[0]);
182 element_table[0] = A0;
183 element_table[1] = A1;
184 } else if constexpr (length == 3) {
185 auto [R0, R1] = inputs[1].checked_unconditional_add_sub(inputs[0]); // B ± A
186
187 auto [T0, T1] = inputs[2].checked_unconditional_add_sub(R0); // C ± (B + A)
188 auto [T2, T3] = inputs[2].checked_unconditional_add_sub(R1); // C ± (B - A)
189
190 element_table[0] = T0;
191 element_table[1] = T2;
192 element_table[2] = T3;
193 element_table[3] = T1;
194 } else if constexpr (length == 4) {
195 auto [T0, T1] = inputs[1].checked_unconditional_add_sub(inputs[0]); // B ± A
196 auto [T2, T3] = inputs[3].checked_unconditional_add_sub(inputs[2]); // D ± C
197
198 auto [F0, F3] = T2.checked_unconditional_add_sub(T0); // (D + C) ± (B + A)
199 auto [F1, F2] = T2.checked_unconditional_add_sub(T1); // (D + C) ± (B - A)
200 auto [F4, F7] = T3.checked_unconditional_add_sub(T0); // (D - C) ± (B + A)
201 auto [F5, F6] = T3.checked_unconditional_add_sub(T1); // (D - C) ± (B - A)
202
203 element_table[0] = F0;
204 element_table[1] = F1;
205 element_table[2] = F2;
206 element_table[3] = F3;
207 element_table[4] = F4;
208 element_table[5] = F5;
209 element_table[6] = F6;
210 element_table[7] = F7;
211 } else if constexpr (length == 5) {
212 auto [A0, A1] = inputs[1].checked_unconditional_add_sub(inputs[0]); // B ± A
213 auto [T2, T3] = inputs[3].checked_unconditional_add_sub(inputs[2]); // D ± C
214
215 auto [E0, E3] = inputs[4].checked_unconditional_add_sub(T2); // E ± (D + C)
216 auto [E1, E2] = inputs[4].checked_unconditional_add_sub(T3); // E ± (D - C)
217
218 auto [F0, F3] = E0.checked_unconditional_add_sub(A0); // E + (D + C) ± (B + A)
219 auto [F1, F2] = E0.checked_unconditional_add_sub(A1); // E + (D + C) ± (B - A)
220 auto [F4, F7] = E1.checked_unconditional_add_sub(A0); // E + (D - C) ± (B + A)
221 auto [F5, F6] = E1.checked_unconditional_add_sub(A1); // E + (D - C) ± (B - A)
222 auto [F8, F11] = E2.checked_unconditional_add_sub(A0); // E - (D - C) ± (B + A)
223 auto [F9, F10] = E2.checked_unconditional_add_sub(A1); // E - (D - C) ± (B - A)
224 auto [F12, F15] = E3.checked_unconditional_add_sub(A0); // E - (D + C) ± (B + A)
225 auto [F13, F14] = E3.checked_unconditional_add_sub(A1); // E - (D + C) ± (B - A)
226
227 element_table[0] = F0;
228 element_table[1] = F1;
229 element_table[2] = F2;
230 element_table[3] = F3;
231 element_table[4] = F4;
232 element_table[5] = F5;
233 element_table[6] = F6;
234 element_table[7] = F7;
235 element_table[8] = F8;
236 element_table[9] = F9;
237 element_table[10] = F10;
238 element_table[11] = F11;
239 element_table[12] = F12;
240 element_table[13] = F13;
241 element_table[14] = F14;
242 element_table[15] = F15;
243 } else if constexpr (length == 6) {
244 // 44 adds! Only use this if it saves us adding another table to a multi-scalar-multiplication
245
246 auto [A0, A1] = inputs[1].checked_unconditional_add_sub(inputs[0]);
247 auto [E0, E1] = inputs[4].checked_unconditional_add_sub(inputs[3]);
248 auto [C0, C3] = inputs[2].checked_unconditional_add_sub(A0);
249 auto [C1, C2] = inputs[2].checked_unconditional_add_sub(A1);
250
251 auto [F0, F3] = inputs[5].checked_unconditional_add_sub(E0);
252 auto [F1, F2] = inputs[5].checked_unconditional_add_sub(E1);
253
254 auto [R0, R7] = F0.checked_unconditional_add_sub(C0);
255 auto [R1, R6] = F0.checked_unconditional_add_sub(C1);
256 auto [R2, R5] = F0.checked_unconditional_add_sub(C2);
257 auto [R3, R4] = F0.checked_unconditional_add_sub(C3);
258
259 auto [S0, S7] = F1.checked_unconditional_add_sub(C0);
260 auto [S1, S6] = F1.checked_unconditional_add_sub(C1);
261 auto [S2, S5] = F1.checked_unconditional_add_sub(C2);
262 auto [S3, S4] = F1.checked_unconditional_add_sub(C3);
263
264 auto [U0, U7] = F2.checked_unconditional_add_sub(C0);
265 auto [U1, U6] = F2.checked_unconditional_add_sub(C1);
266 auto [U2, U5] = F2.checked_unconditional_add_sub(C2);
267 auto [U3, U4] = F2.checked_unconditional_add_sub(C3);
268
269 auto [W0, W7] = F3.checked_unconditional_add_sub(C0);
270 auto [W1, W6] = F3.checked_unconditional_add_sub(C1);
271 auto [W2, W5] = F3.checked_unconditional_add_sub(C2);
272 auto [W3, W4] = F3.checked_unconditional_add_sub(C3);
273
274 element_table[0] = R0;
275 element_table[1] = R1;
276 element_table[2] = R2;
277 element_table[3] = R3;
278 element_table[4] = R4;
279 element_table[5] = R5;
280 element_table[6] = R6;
281 element_table[7] = R7;
282
283 element_table[8] = S0;
284 element_table[9] = S1;
285 element_table[10] = S2;
286 element_table[11] = S3;
287 element_table[12] = S4;
288 element_table[13] = S5;
289 element_table[14] = S6;
290 element_table[15] = S7;
291
292 element_table[16] = U0;
293 element_table[17] = U1;
294 element_table[18] = U2;
295 element_table[19] = U3;
296 element_table[20] = U4;
297 element_table[21] = U5;
298 element_table[22] = U6;
299 element_table[23] = U7;
300
301 element_table[24] = W0;
302 element_table[25] = W1;
303 element_table[26] = W2;
304 element_table[27] = W3;
305 element_table[28] = W4;
306 element_table[29] = W5;
307 element_table[30] = W6;
308 element_table[31] = W7;
309 }
310 for (size_t i = 0; i < table_size / 2; ++i) {
311 element_table[i + (table_size / 2)] = (-element_table[(table_size / 2) - 1 - i]);
312 }
313 coordinates = create_group_element_rom_tables<table_size>(element_table, limb_max);
314}
315
316template <typename C, class Fq, class Fr, class G>
317template <size_t length>
319 const std::array<bool_ct, length>& bits) const
320{
321 std::vector<field_ct> accumulators;
322 for (size_t i = 0; i < length; ++i) {
323 accumulators.emplace_back(field_ct(bits[i]) * (1ULL << i));
324 }
325 field_ct index = field_ct::accumulate(accumulators);
326 return read_group_element_rom_tables<table_size>(coordinates, index, limb_max);
327}
328
360template <typename C, class Fq, class Fr, class G>
364{
367 element d2 = input.dbl();
368
369 P1.element_table[8] = input;
370 for (size_t i = 9; i < 16; ++i) {
371 P1.element_table[i] = P1.element_table[i - 1] + d2;
372 }
373 for (size_t i = 0; i < 8; ++i) {
374 P1.element_table[i] = (-P1.element_table[15 - i]);
375 }
376 for (size_t i = 0; i < 16; ++i) {
377 endoP1.element_table[i]._y = P1.element_table[15 - i]._y;
378 }
380 Fq beta(bb::fr(beta_val.slice(0, 136)), bb::fr(beta_val.slice(136, 256)));
381 for (size_t i = 0; i < 8; ++i) {
382 endoP1.element_table[i]._x = P1.element_table[i]._x * beta;
383 endoP1.element_table[15 - i]._x = endoP1.element_table[i]._x;
384 }
385 P1.coordinates = create_group_element_rom_tables<16>(P1.element_table, P1.limb_max);
386 endoP1.coordinates = create_group_element_rom_tables<16>(endoP1.element_table, endoP1.limb_max);
388 return result;
389}
390
391} // namespace bb::stdlib::element_default
constexpr uint256_t slice(uint64_t start, uint64_t end) const
std::array< element, 2 > checked_unconditional_add_sub(const element &other) const
Compute both add and subtract (a + b, a - b) results simultaneously.
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1167
static std::pair< field_pt, field_pt > read_pair_from_table(const plookup::MultiTableId id, const field_pt &key)
Definition plookup.cpp:70
uint8_t const size_t length
Definition data_store.hpp:9
stdlib::field_t< Builder > field_ct
AvmProvingInputs inputs
@ SECP256K1
Definition types.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field cube_root_of_unity()
Four-bit variable-base table for scalar multiplication.
Definition biggroup.hpp:576
std::array< uint256_t, Fq::NUM_LIMBS *2 > limb_max
Definition biggroup.hpp:592
std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > coordinates
Definition biggroup.hpp:591
void throw_or_abort(std::string const &err)