barretenberg
Loading...
Searching...
No Matches
ultra.hpp
1#pragma once
2#include "barretenberg/commitment_schemes/kzg/kzg.hpp"
3#include "barretenberg/ecc/curves/bn254/g1.hpp"
5#include "barretenberg/flavor/flavor_macros.hpp"
6#include "barretenberg/polynomials/barycentric.hpp"
7#include "barretenberg/polynomials/evaluation_domain.hpp"
8#include "barretenberg/polynomials/polynomial.hpp"
9#include "barretenberg/polynomials/univariate.hpp"
10#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
11#include "barretenberg/relations/auxiliary_relation.hpp"
12#include "barretenberg/relations/elliptic_relation.hpp"
13#include "barretenberg/relations/gen_perm_sort_relation.hpp"
14#include "barretenberg/relations/lookup_relation.hpp"
15#include "barretenberg/relations/permutation_relation.hpp"
16#include "barretenberg/relations/ultra_arithmetic_relation.hpp"
17#include "barretenberg/transcript/transcript.hpp"
18
19namespace proof_system::honk::flavor {
20
21class Ultra {
22 public:
24 using Curve = curve::BN254;
25 using FF = Curve::ScalarField;
26 using GroupElement = Curve::Element;
27 using Commitment = Curve::AffineElement;
28 using CommitmentHandle = Curve::AffineElement;
31 using PolynomialHandle = std::span<FF>;
34
35 static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES;
36 // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often
37 // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS`.
38 // Note: this number does not include the individual sorted list polynomials.
39 static constexpr size_t NUM_ALL_ENTITIES = 43;
40 // The number of polynomials precomputed to describe a circuit and to aid a prover in constructing a satisfying
41 // assignment of witnesses. We again choose a neutral name.
42 static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 25;
43 // The total number of witness entities not including shifts.
44 static constexpr size_t NUM_WITNESS_ENTITIES = 7;
45
46 using GrandProductRelations =
47 std::tuple<proof_system::UltraPermutationRelation<FF>, proof_system::LookupRelation<FF>>;
48 // define the tuple of Relations that comprise the Sumcheck relation
49 using Relations = std::tuple<proof_system::UltraArithmeticRelation<FF>,
55
56 static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length<Relations>();
57 static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length<Relations>();
58 static_assert(MAX_PARTIAL_RELATION_LENGTH == 6);
59 static_assert(MAX_TOTAL_RELATION_LENGTH == 12);
60 static constexpr size_t NUMBER_OF_SUBRELATIONS = compute_number_of_subrelations<Relations>();
61
62 // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta`
63 // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation
64 // length = 3
65 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1;
66 static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1;
67 static constexpr size_t NUM_RELATIONS = std::tuple_size_v<Relations>;
68
69 template <size_t NUM_INSTANCES>
70 using ProtogalaxyTupleOfTuplesOfUnivariates =
71 decltype(create_protogalaxy_tuple_of_tuples_of_univariates<Relations, NUM_INSTANCES>());
72 using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates<Relations>());
73 using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values<Relations>());
74
75 // Whether or not the first row of the execution trace is reserved for 0s to enable shifts
76 static constexpr bool has_zero_row = true;
77
78 private:
83 template <typename DataType_> class PrecomputedEntities : public PrecomputedEntitiesBase {
84 public:
85 using DataType = DataType_;
86 DEFINE_FLAVOR_MEMBERS(DataType,
87 q_m, // column 0
88 q_c, // column 1
89 q_l, // column 2
90 q_r, // column 3
91 q_o, // column 4
92 q_4, // column 5
93 q_arith, // column 6
94 q_sort, // column 7
95 q_elliptic, // column 8
96 q_aux, // column 9
97 q_lookup, // column 10
98 sigma_1, // column 11
99 sigma_2, // column 12
100 sigma_3, // column 13
101 sigma_4, // column 14
102 id_1, // column 15
103 id_2, // column 16
104 id_3, // column 17
105 id_4, // column 18
106 table_1, // column 19
107 table_2, // column 20
108 table_3, // column 21
109 table_4, // column 22
110 lagrange_first, // column 23
111 lagrange_last) // column 24
112
113 static constexpr CircuitType CIRCUIT_TYPE = CircuitBuilder::CIRCUIT_TYPE;
114
115 RefVector<DataType> get_selectors()
116 {
117 return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup };
118 };
119 RefVector<DataType> get_sigma_polynomials() { return { sigma_1, sigma_2, sigma_3, sigma_4 }; };
120 RefVector<DataType> get_id_polynomials() { return { id_1, id_2, id_3, id_4 }; };
121
122 RefVector<DataType> get_table_polynomials() { return { table_1, table_2, table_3, table_4 }; };
123 };
124
129 template <typename DataType> class WitnessEntities {
130 public:
131 DEFINE_FLAVOR_MEMBERS(DataType,
132 w_l, // column 0
133 w_r, // column 1
134 w_o, // column 2
135 w_4, // column 3
136 sorted_accum, // column 4
137 z_perm, // column 5
138 z_lookup) // column 6
139
140 RefVector<DataType> get_wires() { return { w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; };
141 };
142
146 template <typename DataType> class ShiftedEntities {
147 public:
148 DEFINE_FLAVOR_MEMBERS(DataType,
149 table_1_shift, // column 0
150 table_2_shift, // column 1
151 table_3_shift, // column 2
152 table_4_shift, // column 3
153 w_l_shift, // column 4
154 w_r_shift, // column 5
155 w_o_shift, // column 6
156 w_4_shift, // column 7
157 sorted_accum_shift, // column 8
158 z_perm_shift, // column 9
159 z_lookup_shift) // column 10
160
161 RefVector<DataType> get_shifted()
162 {
163 return { table_1_shift, table_2_shift, table_3_shift, table_4_shift, w_l_shift, w_r_shift,
164 w_o_shift, w_4_shift, sorted_accum_shift, z_perm_shift, z_lookup_shift };
165 };
166 };
167
177 template <typename DataType> class AllEntities {
178 public:
179 DEFINE_FLAVOR_MEMBERS(DataType,
180 q_c, // column 0
181 q_l, // column 1
182 q_r, // column 2
183 q_o, // column 3
184 q_4, // column 4
185 q_m, // column 5
186 q_arith, // column 6
187 q_sort, // column 7
188 q_elliptic, // column 8
189 q_aux, // column 9
190 q_lookup, // column 10
191 sigma_1, // column 11
192 sigma_2, // column 12
193 sigma_3, // column 13
194 sigma_4, // column 14
195 id_1, // column 15
196 id_2, // column 16
197 id_3, // column 17
198 id_4, // column 18
199 table_1, // column 19
200 table_2, // column 20
201 table_3, // column 21
202 table_4, // column 22
203 lagrange_first, // column 23
204 lagrange_last, // column 24
205 w_l, // column 25
206 w_r, // column 26
207 w_o, // column 27
208 w_4, // column 28
209 sorted_accum, // column 29
210 z_perm, // column 30
211 z_lookup, // column 31
212 table_1_shift, // column 32
213 table_2_shift, // column 33
214 table_3_shift, // column 34
215 table_4_shift, // column 35
216 w_l_shift, // column 36
217 w_r_shift, // column 37
218 w_o_shift, // column 38
219 w_4_shift, // column 39
220 sorted_accum_shift, // column 40
221 z_perm_shift, // column 41
222 z_lookup_shift) // column 42
223
224 RefVector<DataType> get_wires() { return { w_l, w_r, w_o, w_4 }; };
225 // Gemini-specific getters.
226 RefVector<DataType> get_unshifted()
227 {
228 return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort,
229 q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1,
230 id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first,
231 lagrange_last, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup
232
233 };
234 };
235
236 RefVector<DataType> get_precomputed()
237 {
238 return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort,
239 q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1,
240 id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first,
241 lagrange_last
242
243 };
244 }
245
246 RefVector<DataType> get_witness() { return { w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; };
247 RefVector<DataType> get_to_be_shifted()
248 {
249 return { table_1, table_2, table_3, table_4, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup };
250 };
251 RefVector<DataType> get_shifted()
252 {
253 return { table_1_shift, table_2_shift, table_3_shift, table_4_shift, w_l_shift, w_r_shift,
254 w_o_shift, w_4_shift, sorted_accum_shift, z_perm_shift, z_lookup_shift };
255 };
256 };
257
258 public:
264 class ProvingKey : public ProvingKey_<PrecomputedEntities<Polynomial>, WitnessEntities<Polynomial>> {
265 public:
266 // Expose constructors on the base class
267 using Base = ProvingKey_<PrecomputedEntities<Polynomial>, WitnessEntities<Polynomial>>;
268 using Base::Base;
269
270 std::vector<uint32_t> memory_read_records;
271 std::vector<uint32_t> memory_write_records;
272
273 RefVector<DataType> get_to_be_shifted()
274 {
275 return { this->table_1, this->table_2, this->table_3, this->table_4, this->w_l, this->w_r,
276 this->w_o, this->w_4, this->sorted_accum, this->z_perm, this->z_lookup };
277 };
278 // The plookup wires that store plookup read data.
279 std::array<PolynomialHandle, 3> get_table_column_wires() { return { w_l, w_r, w_o }; };
280 };
281
291
296 class AllValues : public AllEntities<FF> {
297 public:
298 using Base = AllEntities<FF>;
299 using Base::Base;
300 };
301
305 class ProverPolynomials : public AllEntities<Polynomial> {
306 public:
307 // Define all operations as default, except move construction/assignment
308 ProverPolynomials() = default;
309 ProverPolynomials& operator=(const ProverPolynomials&) = delete;
310 ProverPolynomials(const ProverPolynomials& o) = delete;
311 ProverPolynomials(ProverPolynomials&& o) noexcept = default;
312 ProverPolynomials& operator=(ProverPolynomials&& o) noexcept = default;
313 ~ProverPolynomials() = default;
314 [[nodiscard]] size_t get_polynomial_size() const { return q_c.size(); }
315 [[nodiscard]] AllValues get_row(const size_t row_idx) const
316 {
317 AllValues result;
318 for (auto [result_field, polynomial] : zip_view(result.get_all(), get_all())) {
319 result_field = polynomial[row_idx];
320 }
321 return result;
322 }
323 };
324
328 class PartiallyEvaluatedMultivariates : public AllEntities<Polynomial> {
329
330 public:
332 PartiallyEvaluatedMultivariates(const size_t circuit_size)
333 {
334 // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2)
335 for (auto& poly : this->get_all()) {
336 poly = Polynomial(circuit_size / 2);
337 }
338 }
339 };
340
345 template <size_t LENGTH> using ProverUnivariates = AllEntities<barretenberg::Univariate<FF, LENGTH>>;
346
351
355 using WitnessCommitments = WitnessEntities<Commitment>;
356
363 class CommitmentLabels : public AllEntities<std::string> {
364 public:
366 {
367 w_l = "W_L";
368 w_r = "W_R";
369 w_o = "W_O";
370 w_4 = "W_4";
371 z_perm = "Z_PERM";
372 z_lookup = "Z_LOOKUP";
373 sorted_accum = "SORTED_ACCUM";
374
375 q_c = "Q_C";
376 q_l = "Q_L";
377 q_r = "Q_R";
378 q_o = "Q_O";
379 q_4 = "Q_4";
380 q_m = "Q_M";
381 q_arith = "Q_ARITH";
382 q_sort = "Q_SORT";
383 q_elliptic = "Q_ELLIPTIC";
384 q_aux = "Q_AUX";
385 q_lookup = "Q_LOOKUP";
386 sigma_1 = "SIGMA_1";
387 sigma_2 = "SIGMA_2";
388 sigma_3 = "SIGMA_3";
389 sigma_4 = "SIGMA_4";
390 id_1 = "ID_1";
391 id_2 = "ID_2";
392 id_3 = "ID_3";
393 id_4 = "ID_4";
394 table_1 = "TABLE_1";
395 table_2 = "TABLE_2";
396 table_3 = "TABLE_3";
397 table_4 = "TABLE_4";
398 lagrange_first = "LAGRANGE_FIRST";
399 lagrange_last = "LAGRANGE_LAST";
400 };
401 };
402
403 class VerifierCommitments : public AllEntities<Commitment> {
404 public:
405 VerifierCommitments(const std::shared_ptr<VerificationKey>& verification_key)
406 {
407 q_m = verification_key->q_m;
408 q_c = verification_key->q_c;
409 q_l = verification_key->q_l;
410 q_r = verification_key->q_r;
411 q_o = verification_key->q_o;
412 q_4 = verification_key->q_4;
413 q_arith = verification_key->q_arith;
414 q_sort = verification_key->q_sort;
415 q_elliptic = verification_key->q_elliptic;
416 q_aux = verification_key->q_aux;
417 q_lookup = verification_key->q_lookup;
418 sigma_1 = verification_key->sigma_1;
419 sigma_2 = verification_key->sigma_2;
420 sigma_3 = verification_key->sigma_3;
421 sigma_4 = verification_key->sigma_4;
422 id_1 = verification_key->id_1;
423 id_2 = verification_key->id_2;
424 id_3 = verification_key->id_3;
425 id_4 = verification_key->id_4;
426 table_1 = verification_key->table_1;
427 table_2 = verification_key->table_2;
428 table_3 = verification_key->table_3;
429 table_4 = verification_key->table_4;
430 lagrange_first = verification_key->lagrange_first;
431 lagrange_last = verification_key->lagrange_last;
432 }
433 };
434
436 public:
437 std::vector<FF> gate_challenges;
438 FF target_sum;
439 };
440
445 class Transcript : public BaseTranscript {
446 public:
447 // Transcript objects defined as public member variables for easy access and modification
448 uint32_t circuit_size;
449 uint32_t public_input_size;
450 uint32_t pub_inputs_offset;
451 std::vector<FF> public_inputs;
452 Commitment w_l_comm;
453 Commitment w_r_comm;
454 Commitment w_o_comm;
455 Commitment sorted_accum_comm;
456 Commitment w_4_comm;
457 Commitment z_perm_comm;
458 Commitment z_lookup_comm;
459 std::vector<barretenberg::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>> sumcheck_univariates;
460 std::array<FF, NUM_ALL_ENTITIES> sumcheck_evaluations;
461 std::vector<Commitment> zm_cq_comms;
462 Commitment zm_cq_comm;
463 Commitment zm_pi_comm;
464
465 Transcript() = default;
466
467 // Used by verifier to initialize the transcript
468 Transcript(const std::vector<uint8_t>& proof)
469 : BaseTranscript(proof)
470 {}
471
472 static std::shared_ptr<Transcript> prover_init_empty()
473 {
474 auto transcript = std::make_shared<Transcript>();
475 constexpr uint32_t init{ 42 }; // arbitrary
476 transcript->send_to_verifier("Init", init);
477 return transcript;
478 };
479
480 static std::shared_ptr<Transcript> verifier_init_empty(const std::shared_ptr<Transcript>& transcript)
481 {
482 auto verifier_transcript = std::make_shared<Transcript>(transcript->proof_data);
483 [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover<uint32_t>("Init");
484 return verifier_transcript;
485 };
486
493 {
494 // take current proof and put them into the struct
495 size_t num_bytes_read = 0;
496 circuit_size = deserialize_from_buffer<uint32_t>(proof_data, num_bytes_read);
497 size_t log_n = numeric::get_msb(circuit_size);
498
499 public_input_size = deserialize_from_buffer<uint32_t>(proof_data, num_bytes_read);
500 pub_inputs_offset = deserialize_from_buffer<uint32_t>(proof_data, num_bytes_read);
501 for (size_t i = 0; i < public_input_size; ++i) {
502 public_inputs.push_back(deserialize_from_buffer<FF>(proof_data, num_bytes_read));
503 }
504 w_l_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
505 w_r_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
506 w_o_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
507 sorted_accum_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
508 w_4_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
509 z_perm_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
510 z_lookup_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
511 for (size_t i = 0; i < log_n; ++i) {
512 sumcheck_univariates.push_back(
514 proof_data, num_bytes_read));
515 }
516 sumcheck_evaluations =
517 deserialize_from_buffer<std::array<FF, NUM_ALL_ENTITIES>>(proof_data, num_bytes_read);
518 for (size_t i = 0; i < log_n; ++i) {
519 zm_cq_comms.push_back(deserialize_from_buffer<Commitment>(proof_data, num_bytes_read));
520 }
521 zm_cq_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
522 zm_pi_comm = deserialize_from_buffer<Commitment>(proof_data, num_bytes_read);
523 }
530 {
531 size_t old_proof_length = proof_data.size();
532 proof_data.clear(); // clear proof_data so the rest of the function can replace it
533 size_t log_n = numeric::get_msb(circuit_size);
534 serialize_to_buffer(circuit_size, proof_data);
535 serialize_to_buffer(public_input_size, proof_data);
536 serialize_to_buffer(pub_inputs_offset, proof_data);
537 for (size_t i = 0; i < public_input_size; ++i) {
538 serialize_to_buffer(public_inputs[i], proof_data);
539 }
540 serialize_to_buffer(w_l_comm, proof_data);
541 serialize_to_buffer(w_r_comm, proof_data);
542 serialize_to_buffer(w_o_comm, proof_data);
543 serialize_to_buffer(sorted_accum_comm, proof_data);
544 serialize_to_buffer(w_4_comm, proof_data);
545 serialize_to_buffer(z_perm_comm, proof_data);
546 serialize_to_buffer(z_lookup_comm, proof_data);
547 for (size_t i = 0; i < log_n; ++i) {
548 serialize_to_buffer(sumcheck_univariates[i], proof_data);
549 }
550 serialize_to_buffer(sumcheck_evaluations, proof_data);
551 for (size_t i = 0; i < log_n; ++i) {
552 serialize_to_buffer(zm_cq_comms[i], proof_data);
553 }
554 serialize_to_buffer(zm_cq_comm, proof_data);
555 serialize_to_buffer(zm_pi_comm, proof_data);
556
557 // sanity check to make sure we generate the same length of proof as before.
558 ASSERT(proof_data.size() == old_proof_length);
559 }
560 };
561};
562
563} // namespace proof_system::honk::flavor
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
Definition: ref_vector.hpp:20
Definition: polynomial.hpp:12
A univariate polynomial represented by its values on {domain_start, domain_start + 1,...
Definition: univariate.hpp:23
Definition: bn254.hpp:10
The templates defined herein facilitate sharing the relation arithmetic between the prover and the ve...
Definition: relation_types.hpp:121
Definition: ultra_circuit_builder.hpp:31
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
Definition: transcript.hpp:62
T deserialize_from_buffer(const Proof &proof_data, size_t &offset) const
Deserializes the bytes starting at offset into the typed element and returns that element.
Definition: transcript.hpp:180
void serialize_to_buffer(const T &element, Proof &proof_data)
Serializes object and appends it to proof_data.
Definition: transcript.hpp:166
Base class template containing circuit-specifying data.
Definition: flavor.hpp:85
Base proving key class.
Definition: flavor.hpp:101
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
Definition: ultra.hpp:296
A container for commitment labels.
Definition: ultra.hpp:363
A container for storing the partially evaluated multivariates produced by sumcheck.
Definition: ultra.hpp:328
A container for polynomials handles.
Definition: ultra.hpp:305
The proving key is responsible for storing the polynomials used by the prover.
Definition: ultra.hpp:264
Derived class that defines proof structure for Ultra proofs, as well as supporting functions.
Definition: ultra.hpp:445
void deserialize_full_transcript()
Takes a FULL Ultra proof and deserializes it into the public member variables that compose the struct...
Definition: ultra.hpp:492
void serialize_full_transcript()
Serializes the structure variables into a FULL Ultra proof. Should be called only if deserialize_full...
Definition: ultra.hpp:529
Definition: ultra.hpp:21
WitnessEntities< Commitment > WitnessCommitments
A container for the witness commitments.
Definition: ultra.hpp:355
ProverUnivariates< MAX_PARTIAL_RELATION_LENGTH > ExtendedEdges
A container for univariates produced during the hot loop in sumcheck.
Definition: ultra.hpp:350
AllEntities< barretenberg::Univariate< FF, LENGTH > > ProverUnivariates
A container for univariates used during Protogalaxy folding and sumcheck.
Definition: ultra.hpp:345
CommitmentKey object over a pairing group 𝔾₁.
Definition: commitment_key.hpp:35
Definition: verification_key.hpp:25
Definition: kzg.hpp:14
Definition: zip_view.hpp:159
Base class templates for structures that contain data parameterized by the fundamental polynomials of...