Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm.test.cpp
Go to the documentation of this file.
1#include <cstddef>
2#include <cstdint>
3#include <gtest/gtest.h>
4#include <vector>
5
19
20using namespace bb;
27
28// Test helper: Create a VK by committing to proving key polynomials (for comparing with fixed VK)
30{
32 // Overwrite fixed commitments with computed commitments from the proving key
33 for (auto [polynomial, commitment] : zip_view(proving_key->polynomials.get_precomputed(), vk.get_all())) {
34 commitment = proving_key->commitment_key.commit(polynomial);
35 }
36 return vk;
37}
38
39// Compute VK hash from fixed commitments (for test verification that vk_hash() is correct)
41{
43 // Serialize commitments using the Codec
44 for (const auto& commitment : ECCVMHardcodedVKAndHash::get_all()) {
45 auto frs = ECCVMFlavor::Codec::serialize_to_fields(commitment);
46 for (const auto& fr : frs) {
47 elements.push_back(fr);
48 }
49 }
50 return ECCVMFlavor::HashFunction::hash(elements);
51}
52
53class ECCVMTests : public ::testing::Test {
54 protected:
56};
57namespace {
59} // namespace
60
68{
69 using Curve = curve::BN254;
70 using G1 = Curve::Element;
71 using Fr = Curve::ScalarField;
72
74 G1 a = G1::random_element(engine);
75 G1 b = G1::random_element(engine);
76 G1 c = G1::random_element(engine);
79
80 op_queue->add_accumulate(a);
81 op_queue->mul_accumulate(a, x);
82 op_queue->mul_accumulate(b, x);
83 op_queue->mul_accumulate(b, y);
84 op_queue->add_accumulate(a);
85 op_queue->mul_accumulate(b, x);
86 op_queue->eq_and_reset();
87 op_queue->add_accumulate(c);
88 op_queue->mul_accumulate(a, x);
89 op_queue->mul_accumulate(b, x);
90 op_queue->eq_and_reset();
91 op_queue->mul_accumulate(a, x);
92 op_queue->mul_accumulate(b, x);
93 op_queue->mul_accumulate(c, x);
94 op_queue->merge();
95 add_hiding_op_for_test(op_queue);
96 ECCVMCircuitBuilder builder{ op_queue };
97 return builder;
98}
99
100// returns a CircuitBuilder consisting of mul_add ops of the following form: either 0*g, for a group element, or
101// x * e, where x is a scalar and e is the identity element of the group.
102ECCVMCircuitBuilder generate_zero_circuit([[maybe_unused]] numeric::RNG* engine = nullptr, bool zero_scalars = 1)
103{
104 using Curve = curve::BN254;
105 using G1 = Curve::Element;
106 using Fr = Curve::ScalarField;
107
109
110 if (!zero_scalars) {
111 for (auto i = 0; i < 8; i++) {
113 op_queue->mul_accumulate(Curve::Group::affine_point_at_infinity, x);
114 }
115 } else {
116 for (auto i = 0; i < 8; i++) {
117 G1 g = G1::random_element(engine);
118 op_queue->mul_accumulate(g, 0);
119 }
120 }
121 op_queue->merge();
122 add_hiding_op_for_test(op_queue);
123
124 ECCVMCircuitBuilder builder{ op_queue };
125 return builder;
126}
127
130 std::vector<FF>& gate_challenges)
131{
132 // Prepare the inputs for the sumcheck prover:
133 // Compute and add beta to relation parameters
134 const FF beta = FF::random_element();
135 const FF gamma = FF::random_element();
136 const FF beta_sqr = beta * beta;
137 const FF beta_quartic = beta_sqr * beta_sqr;
138 relation_parameters.gamma = gamma;
139 relation_parameters.beta = beta;
140 relation_parameters.beta_sqr = beta_sqr;
141 relation_parameters.beta_cube = beta_sqr * beta;
142 relation_parameters.beta_quartic = beta_quartic;
143 auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic
144 relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) *
145 (gamma + beta_sqr + beta_sqr + first_term_tag) *
146 (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag);
147 relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert();
148
149 const size_t unmasked_witness_size = pk->circuit_size - NUM_DISABLED_ROWS_IN_SUMCHECK;
150 // Compute z_perm and inverse polynomial for our logarithmic-derivative lookup method
151 compute_logderivative_inverse<FF, ECCVMFlavor::LookupRelation, ECCVMFlavor::ProverPolynomials, true>(
152 pk->polynomials, relation_parameters, unmasked_witness_size);
153 compute_grand_products<ECCVMFlavor>(pk->polynomials, relation_parameters, unmasked_witness_size);
154
155 // Generate gate challenges
156 for (size_t idx = 0; idx < CONST_ECCVM_LOG_N; idx++) {
157 gate_challenges[idx] = FF::random_element();
158 }
159}
160TEST_F(ECCVMTests, ZeroesCoefficients)
161{
163
164 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
165 ECCVMProver prover(builder, prover_transcript);
166 auto [proof, opening_claim] = prover.construct_proof();
167
168 // Compute IPA proof
169 auto ipa_transcript = std::make_shared<Transcript>();
170 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
171
172 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
173 ECCVMVerifier verifier(verifier_transcript, proof);
174 auto eccvm_result = verifier.reduce_to_ipa_opening();
175
176 // Verify IPA
177 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
179 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
180
181 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
182}
183// Calling get_eccvm_ops without a hiding op should throw
184TEST_F(ECCVMTests, MissingHidingOpThrows)
185{
187 // get_eccvm_ops() requires a hiding op to have been set; throws "Hiding op must be set before calling
188 // get_eccvm_ops()"
189 EXPECT_THROW(op_queue->get_eccvm_ops(), std::runtime_error);
190}
191
192// Note that `NullOpQueue` is somewhat misleading, as we add a hiding operation.
193TEST_F(ECCVMTests, NullOpQUeue)
194{
196 add_hiding_op_for_test(op_queue);
197 ECCVMCircuitBuilder builder{ op_queue };
198 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
199 ECCVMProver prover(builder, prover_transcript);
200 auto [proof, opening_claim] = prover.construct_proof();
201
202 // Compute IPA proof
203 auto ipa_transcript = std::make_shared<Transcript>();
204 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
205
206 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
207 ECCVMVerifier verifier(verifier_transcript, proof);
208 auto eccvm_result = verifier.reduce_to_ipa_opening();
209
210 // Verify IPA
211 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
213 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
214
215 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
216}
217
218TEST_F(ECCVMTests, PointAtInfinity)
219{
221
222 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
223 ECCVMProver prover(builder, prover_transcript);
224 auto [proof, opening_claim] = prover.construct_proof();
225
226 auto ipa_transcript = std::make_shared<Transcript>();
227 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
228
229 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
230 ECCVMVerifier verifier(verifier_transcript, proof);
231 auto eccvm_result = verifier.reduce_to_ipa_opening();
232
233 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
235 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
236
237 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
238}
239TEST_F(ECCVMTests, ScalarEdgeCase)
240{
241 using Curve = curve::BN254;
242 using G1 = Curve::Element;
243 using Fr = Curve::ScalarField;
244
246 G1 a = G1::one();
247
248 op_queue->mul_accumulate(a, Fr(uint256_t(1) << 128));
249 op_queue->eq_and_reset();
250 op_queue->merge();
251 add_hiding_op_for_test(op_queue);
252 ECCVMCircuitBuilder builder{ op_queue };
253
254 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
255 ECCVMProver prover(builder, prover_transcript);
256 auto [proof, opening_claim] = prover.construct_proof();
257
258 auto ipa_transcript = std::make_shared<Transcript>();
259 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
260
261 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
262 ECCVMVerifier verifier(verifier_transcript, proof);
263 auto eccvm_result = verifier.reduce_to_ipa_opening();
264
265 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
267 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
268
269 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
270}
278TEST_F(ECCVMTests, ProofLengthCheck)
279{
281
282 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
283 ECCVMProver prover(builder, prover_transcript);
284 auto [proof, opening_claim] = prover.construct_proof();
285 EXPECT_EQ(proof.size(), ECCVMFlavor::PROOF_LENGTH);
286}
287
288TEST_F(ECCVMTests, BaseCaseFixedSize)
289{
291
292 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
293 ECCVMProver prover(builder, prover_transcript);
294 auto [proof, opening_claim] = prover.construct_proof();
295
296 auto ipa_transcript = std::make_shared<Transcript>();
297 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
298
299 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
300 ECCVMVerifier verifier(verifier_transcript, proof);
301 auto eccvm_result = verifier.reduce_to_ipa_opening();
302
303 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
305 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
306
307 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
308}
309
310TEST_F(ECCVMTests, EqFailsFixedSize)
311{
313 // Tamper with the eq op such that the expected value is incorect
314 builder.op_queue->add_erroneous_equality_op_for_testing();
315 builder.op_queue->merge();
316
317 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
318 ECCVMProver prover(builder, prover_transcript);
319
320 auto [proof, opening_claim] = prover.construct_proof();
321
322 auto ipa_transcript = std::make_shared<Transcript>();
323 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
324
325 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
326 ECCVMVerifier verifier(verifier_transcript, proof);
327 auto eccvm_result = verifier.reduce_to_ipa_opening();
328
329 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
331 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
332
333 ASSERT_FALSE(ipa_verified && eccvm_result.reduction_succeeded);
334}
335
336TEST_F(ECCVMTests, CommittedSumcheck)
337{
338 using Flavor = ECCVMFlavor;
339 using ProvingKey = ECCVMFlavor::ProvingKey;
340 using FF = ECCVMFlavor::FF;
342 using ZKData = ZKSumcheckData<Flavor>;
343
344 bb::RelationParameters<FF> relation_parameters;
345 std::vector<FF> gate_challenges(CONST_ECCVM_LOG_N);
346
348 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
349 ECCVMProver prover(builder, prover_transcript);
351
352 // Prepare the inputs for the sumcheck prover:
353 // Compute and add beta to relation parameters
354 const FF alpha = FF::random_element();
355 complete_proving_key_for_test(relation_parameters, pk, gate_challenges);
356
357 // Clear the transcript
358 prover_transcript = std::make_shared<Transcript>();
359
360 // Run Sumcheck on the ECCVM Prover polynomials
362 SumcheckProver sumcheck_prover(pk->circuit_size,
363 pk->polynomials,
364 prover_transcript,
365 alpha,
366 gate_challenges,
367 relation_parameters,
368 CONST_ECCVM_LOG_N);
369
370 ZKData zk_sumcheck_data = ZKData(CONST_ECCVM_LOG_N, prover_transcript);
371
372 auto prover_output = sumcheck_prover.prove(zk_sumcheck_data);
373
374 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>(prover_transcript->export_proof());
375
376 // Execute Sumcheck Verifier
377 SumcheckVerifier<Flavor> sumcheck_verifier(verifier_transcript, alpha, CONST_ECCVM_LOG_N);
378 std::vector<FF> padding_indicator_array(CONST_ECCVM_LOG_N, FF(1));
379 SumcheckOutput<ECCVMFlavor> verifier_output =
380 sumcheck_verifier.verify(relation_parameters, gate_challenges, padding_indicator_array);
381
382 // Evaluate prover's round univariates at corresponding challenges and compare them with the claimed evaluations
383 // computed by the verifier
384 for (size_t idx = 0; idx < CONST_ECCVM_LOG_N; idx++) {
385 FF true_eval_at_the_challenge = prover_output.round_univariates[idx].evaluate(prover_output.challenge[idx]);
386 FF verifier_eval_at_the_challenge = verifier_output.round_univariate_evaluations[idx][2];
387 EXPECT_TRUE(true_eval_at_the_challenge == verifier_eval_at_the_challenge);
388 }
389
390 // Check that the first sumcheck univariate is consistent with the claimed ZK Sumchek Sum
391 FF prover_target_sum = zk_sumcheck_data.libra_challenge * zk_sumcheck_data.libra_total_sum;
392
393 EXPECT_TRUE(prover_target_sum == verifier_output.round_univariate_evaluations[0][0] +
394 verifier_output.round_univariate_evaluations[0][1]);
395
396 EXPECT_TRUE(verifier_output.verified);
397}
398
414TEST_F(ECCVMTests, BaseInfinityForgedCoordinatesRejected)
415{
416 using Curve = curve::BN254;
417 using G1 = Curve::Element;
418 using Fr = Curve::ScalarField;
419
420 auto generators = Curve::Group::derive_generators("base_infinity_regression", 2);
421 G1 a = generators[0];
422 G1 b = generators[1]; // the point the attacker tries to smuggle in
425
426 // Honest vs forged results
427 G1 honest_result = a * x + b * y;
428 G1 forged_result = a * x;
429 ASSERT_NE(honest_result, forged_result) << "Need b*y != 0 for a meaningful attack";
430
431 // Build the circuit: mul(a, x), mul(infinity, y), eq_and_reset()
432 // The op queue honestly computes a*x + infinity*y = a*x. Eq point = a*x.
433 // The builder sets base_infinity=1 at the second mul row.
435 op_queue->mul_accumulate(a, x);
436 op_queue->mul_accumulate(Curve::Group::affine_point_at_infinity, y);
437 op_queue->eq_and_reset();
438 op_queue->merge();
439 add_hiding_op_for_test(op_queue);
440
441 ECCVMCircuitBuilder builder{ op_queue };
442
443 // Create prover (polynomials are built in the constructor)
444 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
445 ECCVMProver prover(builder, prover_transcript);
446
447 // Find the mul row with base_infinity=1
448 auto& polys = prover.key->polynomials;
449 const size_t num_rows = polys.get_polynomial_size();
450 size_t forged_row = 0;
451 for (size_t i = 0; i < num_rows; i++) {
452 if (polys.transcript_op[i] == FF(4) && polys.transcript_base_infinity[i] == FF(1)) {
453 forged_row = i;
454 break;
455 }
456 }
457 ASSERT_GT(forged_row, size_t(0)) << "Could not find infinity mul row";
458
459 // Replace transcript_Px/Py with valid on-curve point b.
460 // After this, the committed transcript says: mul(a,x), mul(b,y), eq(a*x)
461 // Honest result = a*x + b*y, but the proof will claim a*x.
462 auto b_affine = Curve::Group::affine_element(b);
463 polys.transcript_Px.at(forged_row) = b_affine.x;
464 polys.transcript_Py.at(forged_row) = b_affine.y;
465
466 // Generate proof from modified polynomials
467 auto [proof, opening_claim] = prover.construct_proof();
468
469 // Compute IPA opening proof
470 auto ipa_transcript = std::make_shared<Transcript>();
471 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
472
473 // Verify the ECCVM proof
474 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
475 ECCVMVerifier verifier(verifier_transcript, proof);
476 auto eccvm_result = verifier.reduce_to_ipa_opening();
477
478 // Verify the IPA proof
479 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
481 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
482
483 bool proof_verified = ipa_verified && eccvm_result.reduction_succeeded;
484
485 EXPECT_FALSE(proof_verified)
486 << "REGRESSION: Forged ECCVM proof must NOT verify after base_infinity coordinate constraints";
487}
488
496{
497 // Generate a circuit and its verification key (computed at runtime from the proving key)
499 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
500 ECCVMProver prover(builder, prover_transcript);
501 auto [proof, opening_claim] = prover.construct_proof();
502
503 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
504 ECCVMVerifier verifier(verifier_transcript, proof);
505
506 // Generate the default fixed VK
508 // Generate a VK from PK
509 ECCVMFlavor::VerificationKey vk_computed_by_prover = create_vk_from_proving_key(prover.key);
510
511 const auto& labels = bb::ECCVMFlavor::VerificationKey::get_labels();
512 size_t index = 0;
513 for (auto [vk_commitment, fixed_commitment] : zip_view(vk_computed_by_prover.get_all(), fixed_vk.get_all())) {
514 EXPECT_EQ(vk_commitment, fixed_commitment)
515 << "Mismatch between vk_commitment and fixed_commitment at label: " << labels[index];
516 ++index;
517 }
518
519 // Check that the fixed VK is equal to the generated VK
520 EXPECT_EQ(fixed_vk, vk_computed_by_prover);
521
522 // Verify that the hardcoded VK hash matches the computed hash
523 auto computed_hash = compute_eccvm_vk_hash();
524 auto hardcoded_hash = ECCVMHardcodedVKAndHash::vk_hash();
525 if (computed_hash != hardcoded_hash) {
526 info("VK hash mismatch! Update ECCVMHardcodedVKAndHash::vk_hash() with:");
527 info("0x", computed_hash);
528 }
529 EXPECT_EQ(computed_hash, hardcoded_hash) << "Hardcoded VK hash does not match computed hash";
530}
void SetUp() override
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
The proving key is responsible for storing the polynomials used by the prover.
static constexpr size_t ECCVM_FIXED_SIZE
typename Curve::ScalarField FF
typename Curve::BaseField BF
static constexpr size_t PROOF_LENGTH
BaseTranscript< Codec, HashFunction > Transcript
static constexpr std::vector< Commitment > get_all()
std::pair< Proof, OpeningClaim > construct_proof()
std::shared_ptr< ProvingKey > key
Unified ECCVM verifier class for both native and recursive verification.
ReductionResult reduce_to_ipa_opening()
Reduce the ECCVM proof to an IPA opening claim.
Simple verification key class for fixed-size circuits (ECCVM, Translator, AVM).
Definition flavor.hpp:101
static std::vector< fr > serialize_to_fields(const T &val)
Conversion from transcript values to bb::frs.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:86
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:298
SumcheckOutput< Flavor > prove()
Non-ZK version: Compute round univariate, place it in transcript, compute challenge,...
Definition sumcheck.hpp:396
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:747
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges, const std::vector< FF > &padding_indicator_array)
The Sumcheck verification method. First it extracts round univariate, checks sum (the sumcheck univar...
Definition sumcheck.hpp:803
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
typename Group::element Element
Definition grumpkin.hpp:64
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
void complete_proving_key_for_test(bb::RelationParameters< FF > &relation_parameters, std::shared_ptr< PK > &pk, std::vector< FF > &gate_challenges)
ECCVMFlavor::VerificationKey create_vk_from_proving_key(const std::shared_ptr< PK > &proving_key)
ECCVMFlavor::BF compute_eccvm_vk_hash()
ECCVMFlavor::FF FF
ECCVMCircuitBuilder generate_zero_circuit(numeric::RNG *engine=nullptr, bool zero_scalars=1)
ECCVMCircuitBuilder generate_circuit(numeric::RNG *engine=nullptr)
Adds operations in BN254 to the op_queue and then constructs and ECCVM circuit from the op_queue.
numeric::RNG & engine
void add_hiding_op_for_test(const std::shared_ptr< ECCOpQueue > &op_queue)
Set a hiding op on the op_queue for testing.
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:217
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:155
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
Curve::AffineElement G1
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Contains the evaluations of multilinear polynomials at the challenge point . These are computed by S...
std::vector< std::array< FF, 3 > > round_univariate_evaluations
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
static field random_element(numeric::RNG *engine=nullptr) noexcept