3#include "./eccvm_builder_types.hpp"
4#include "./msm_builder.hpp"
5#include "./precomputed_tables_builder.hpp"
6#include "./transcript_builder.hpp"
7#include "barretenberg/ecc/curves/bn254/fr.hpp"
8#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
9#include "barretenberg/flavor/ecc_vm.hpp"
10#include "barretenberg/honk/proof_system/logderivative_library.hpp"
11#include "barretenberg/honk/proof_system/permutation_library.hpp"
12#include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp"
13#include "barretenberg/relations/relation_parameters.hpp"
15namespace proof_system {
19 using CycleGroup =
typename Flavor::CycleGroup;
20 using FF =
typename Flavor::FF;
23 using CycleScalar =
typename CycleGroup::subgroup_field;
24 using Element =
typename CycleGroup::element;
25 using AffineElement =
typename CycleGroup::affine_element;
27 static constexpr size_t NUM_SCALAR_BITS = proof_system_eccvm::NUM_SCALAR_BITS;
28 static constexpr size_t WNAF_SLICE_BITS = proof_system_eccvm::WNAF_SLICE_BITS;
29 static constexpr size_t NUM_WNAF_SLICES = proof_system_eccvm::NUM_WNAF_SLICES;
30 static constexpr uint64_t WNAF_MASK = proof_system_eccvm::WNAF_MASK;
31 static constexpr size_t POINT_TABLE_SIZE = proof_system_eccvm::POINT_TABLE_SIZE;
32 static constexpr size_t WNAF_SLICES_PER_ROW = proof_system_eccvm::WNAF_SLICES_PER_ROW;
33 static constexpr size_t ADDITIONS_PER_ROW = proof_system_eccvm::ADDITIONS_PER_ROW;
35 static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES;
36 static constexpr size_t NUM_WIRES = Flavor::NUM_WIRES;
38 using MSM = proof_system_eccvm::MSM<CycleGroup>;
40 std::shared_ptr<ECCOpQueue> op_queue;
45 : op_queue(std::make_shared<ECCOpQueue>()){};
48 : op_queue(op_queue){};
50 [[nodiscard]] uint32_t get_number_of_muls()
const
52 uint32_t num_muls = 0;
53 for (
auto& op : op_queue->raw_ops) {
68 const uint32_t num_muls = get_number_of_muls();
72 const auto compute_precomputed_table = [](
const AffineElement& base_point) {
73 const auto d2 = Element(base_point).dbl();
74 std::array<AffineElement, POINT_TABLE_SIZE> table;
75 table[POINT_TABLE_SIZE / 2] = base_point;
76 for (
size_t i = 1; i < POINT_TABLE_SIZE / 2; ++i) {
77 table[i + POINT_TABLE_SIZE / 2] = Element(table[i + POINT_TABLE_SIZE / 2 - 1]) + d2;
79 for (
size_t i = 0; i < POINT_TABLE_SIZE / 2; ++i) {
80 table[i] = -table[POINT_TABLE_SIZE - 1 - i];
84 const auto compute_wnaf_slices = [](
uint256_t scalar) {
85 std::array<int, NUM_WNAF_SLICES> output;
86 int previous_slice = 0;
87 for (
size_t i = 0; i < NUM_WNAF_SLICES; ++i) {
89 uint64_t raw_slice =
static_cast<uint64_t
>(scalar) & WNAF_MASK;
91 bool is_even = ((raw_slice & 1ULL) == 0ULL);
93 int wnaf_slice =
static_cast<int>(raw_slice);
95 if (i == 0 && is_even) {
101 static constexpr int borrow_constant =
static_cast<int>(1ULL << WNAF_SLICE_BITS);
102 previous_slice -= borrow_constant;
107 const size_t idx = i - 1;
108 output[NUM_WNAF_SLICES - idx - 1] = previous_slice;
110 previous_slice = wnaf_slice;
113 scalar = scalar >> WNAF_SLICE_BITS;
118 output[0] = previous_slice;
122 std::vector<MSM> msms;
123 std::vector<ScalarMul> active_msm;
132 uint32_t pc = num_muls;
134 const auto process_mul = [&active_msm, &pc, &compute_wnaf_slices, &compute_precomputed_table](
135 const auto& scalar,
const auto& base_point) {
140 .base_point = base_point,
141 .wnaf_slices = compute_wnaf_slices(scalar),
142 .wnaf_skew = (scalar & 1) == 0,
143 .precomputed_table = compute_precomputed_table(base_point),
149 for (
auto& op : op_queue->raw_ops) {
151 process_mul(op.z1, op.base_point);
152 process_mul(op.z2, AffineElement{ op.base_point.x * FF::cube_root_of_unity(), -op.base_point.y });
155 if (!active_msm.empty()) {
156 msms.push_back(active_msm);
161 if (!active_msm.empty()) {
162 msms.push_back(active_msm);
169 static std::vector<ScalarMul> get_flattened_scalar_muls(
const std::vector<MSM>& msms)
171 std::vector<ScalarMul> result;
172 for (
const auto& msm : msms) {
173 for (
const auto& mul : msm) {
174 result.push_back(mul);
180 void add_accumulate(
const AffineElement& to_add)
182 op_queue->raw_ops.emplace_back(VMOperation{
187 .base_point = to_add,
190 .mul_scalar_full = 0,
194 void mul_accumulate(
const AffineElement& to_mul,
const CycleScalar& scalar)
198 auto converted = scalar.from_montgomery_form();
199 CycleScalar::split_into_endomorphism_scalars(converted, z1, z2);
200 z1 = z1.to_montgomery_form();
201 z2 = z2.to_montgomery_form();
202 op_queue->raw_ops.emplace_back(VMOperation{
207 .base_point = to_mul,
210 .mul_scalar_full = scalar,
214 void eq_and_reset(
const AffineElement& expected)
216 op_queue->raw_ops.emplace_back(VMOperation{
221 .base_point = expected,
224 .mul_scalar_full = 0,
230 op_queue->raw_ops.emplace_back(VMOperation{
235 .base_point = CycleGroup::affine_point_at_infinity,
238 .mul_scalar_full = 0,
323 const auto flattened_muls = get_flattened_scalar_muls(msms);
325 std::array<std::vector<size_t>, 2> point_table_read_counts;
326 const auto transcript_state =
328 const auto precompute_table_state =
330 const auto msm_state =
333 const size_t msm_size = msm_state.size();
334 const size_t transcript_size = transcript_state.size();
335 const size_t precompute_table_size = precompute_table_state.size();
337 const size_t num_rows = std::max(precompute_table_size, std::max(msm_size, transcript_size));
339 const auto num_rows_log2 =
static_cast<size_t>(numeric::get_msb64(num_rows));
340 size_t num_rows_pow2 = 1UL << (num_rows_log2 + (1UL << num_rows_log2 == num_rows ? 0 : 1));
342 ProverPolynomials polys;
343 for (
auto& poly : polys.get_all()) {
344 poly = Polynomial(num_rows_pow2);
347 polys.lagrange_first[0] = 1;
348 polys.lagrange_second[1] = 1;
349 polys.lagrange_last[polys.lagrange_last.size() - 1] = 1;
351 for (
size_t i = 0; i < point_table_read_counts[0].size(); ++i) {
358 polys.lookup_read_counts_0[i + 1] = point_table_read_counts[0][i];
359 polys.lookup_read_counts_1[i + 1] = point_table_read_counts[1][i];
361 for (
size_t i = 0; i < transcript_state.size(); ++i) {
362 polys.transcript_accumulator_empty[i] = transcript_state[i].accumulator_empty;
363 polys.transcript_add[i] = transcript_state[i].q_add;
364 polys.transcript_mul[i] = transcript_state[i].q_mul;
365 polys.transcript_eq[i] = transcript_state[i].q_eq;
366 polys.transcript_reset_accumulator[i] = transcript_state[i].q_reset_accumulator;
367 polys.transcript_msm_transition[i] = transcript_state[i].msm_transition;
368 polys.transcript_pc[i] = transcript_state[i].pc;
369 polys.transcript_msm_count[i] = transcript_state[i].msm_count;
370 polys.transcript_Px[i] = transcript_state[i].base_x;
371 polys.transcript_Py[i] = transcript_state[i].base_y;
372 polys.transcript_z1[i] = transcript_state[i].z1;
373 polys.transcript_z2[i] = transcript_state[i].z2;
374 polys.transcript_z1zero[i] = transcript_state[i].z1_zero;
375 polys.transcript_z2zero[i] = transcript_state[i].z2_zero;
376 polys.transcript_op[i] = transcript_state[i].opcode;
377 polys.transcript_accumulator_x[i] = transcript_state[i].accumulator_x;
378 polys.transcript_accumulator_y[i] = transcript_state[i].accumulator_y;
379 polys.transcript_msm_x[i] = transcript_state[i].msm_output_x;
380 polys.transcript_msm_y[i] = transcript_state[i].msm_output_y;
381 polys.transcript_collision_check[i] = transcript_state[i].collision_check;
387 if (transcript_state[transcript_state.size() - 1].accumulator_empty == 1) {
388 for (
size_t i = transcript_state.size(); i < num_rows_pow2; ++i) {
389 polys.transcript_accumulator_empty[i] = 1;
392 for (
size_t i = 0; i < precompute_table_state.size(); ++i) {
396 polys.precompute_select[i] = (i != 0) ? 1 : 0;
397 polys.precompute_pc[i] = precompute_table_state[i].pc;
398 polys.precompute_point_transition[i] =
static_cast<uint64_t
>(precompute_table_state[i].point_transition);
399 polys.precompute_round[i] = precompute_table_state[i].round;
400 polys.precompute_scalar_sum[i] = precompute_table_state[i].scalar_sum;
402 polys.precompute_s1hi[i] = precompute_table_state[i].s1;
403 polys.precompute_s1lo[i] = precompute_table_state[i].s2;
404 polys.precompute_s2hi[i] = precompute_table_state[i].s3;
405 polys.precompute_s2lo[i] = precompute_table_state[i].s4;
406 polys.precompute_s3hi[i] = precompute_table_state[i].s5;
407 polys.precompute_s3lo[i] = precompute_table_state[i].s6;
408 polys.precompute_s4hi[i] = precompute_table_state[i].s7;
409 polys.precompute_s4lo[i] = precompute_table_state[i].s8;
413 polys.precompute_skew[i] = precompute_table_state[i].skew ? 7 : 0;
415 polys.precompute_dx[i] = precompute_table_state[i].precompute_double.x;
416 polys.precompute_dy[i] = precompute_table_state[i].precompute_double.y;
417 polys.precompute_tx[i] = precompute_table_state[i].precompute_accumulator.x;
418 polys.precompute_ty[i] = precompute_table_state[i].precompute_accumulator.y;
421 for (
size_t i = 0; i < msm_state.size(); ++i) {
422 polys.msm_transition[i] =
static_cast<int>(msm_state[i].msm_transition);
423 polys.msm_add[i] =
static_cast<int>(msm_state[i].q_add);
424 polys.msm_double[i] =
static_cast<int>(msm_state[i].q_double);
425 polys.msm_skew[i] =
static_cast<int>(msm_state[i].q_skew);
426 polys.msm_accumulator_x[i] = msm_state[i].accumulator_x;
427 polys.msm_accumulator_y[i] = msm_state[i].accumulator_y;
428 polys.msm_pc[i] = msm_state[i].pc;
429 polys.msm_size_of_msm[i] = msm_state[i].msm_size;
430 polys.msm_count[i] = msm_state[i].msm_count;
431 polys.msm_round[i] = msm_state[i].msm_round;
432 polys.msm_add1[i] =
static_cast<int>(msm_state[i].add_state[0].add);
433 polys.msm_add2[i] =
static_cast<int>(msm_state[i].add_state[1].add);
434 polys.msm_add3[i] =
static_cast<int>(msm_state[i].add_state[2].add);
435 polys.msm_add4[i] =
static_cast<int>(msm_state[i].add_state[3].add);
436 polys.msm_x1[i] = msm_state[i].add_state[0].point.x;
437 polys.msm_y1[i] = msm_state[i].add_state[0].point.y;
438 polys.msm_x2[i] = msm_state[i].add_state[1].point.x;
439 polys.msm_y2[i] = msm_state[i].add_state[1].point.y;
440 polys.msm_x3[i] = msm_state[i].add_state[2].point.x;
441 polys.msm_y3[i] = msm_state[i].add_state[2].point.y;
442 polys.msm_x4[i] = msm_state[i].add_state[3].point.x;
443 polys.msm_y4[i] = msm_state[i].add_state[3].point.y;
444 polys.msm_collision_x1[i] = msm_state[i].add_state[0].collision_inverse;
445 polys.msm_collision_x2[i] = msm_state[i].add_state[1].collision_inverse;
446 polys.msm_collision_x3[i] = msm_state[i].add_state[2].collision_inverse;
447 polys.msm_collision_x4[i] = msm_state[i].add_state[3].collision_inverse;
448 polys.msm_lambda1[i] = msm_state[i].add_state[0].lambda;
449 polys.msm_lambda2[i] = msm_state[i].add_state[1].lambda;
450 polys.msm_lambda3[i] = msm_state[i].add_state[2].lambda;
451 polys.msm_lambda4[i] = msm_state[i].add_state[3].lambda;
452 polys.msm_slice1[i] = msm_state[i].add_state[0].slice;
453 polys.msm_slice2[i] = msm_state[i].add_state[1].slice;
454 polys.msm_slice3[i] = msm_state[i].add_state[2].slice;
455 polys.msm_slice4[i] = msm_state[i].add_state[3].slice;
458 polys.transcript_mul_shift = Polynomial(polys.transcript_mul.shifted());
459 polys.transcript_msm_count_shift = Polynomial(polys.transcript_msm_count.shifted());
460 polys.transcript_accumulator_x_shift = Polynomial(polys.transcript_accumulator_x.shifted());
461 polys.transcript_accumulator_y_shift = Polynomial(polys.transcript_accumulator_y.shifted());
462 polys.precompute_scalar_sum_shift = Polynomial(polys.precompute_scalar_sum.shifted());
463 polys.precompute_s1hi_shift = Polynomial(polys.precompute_s1hi.shifted());
464 polys.precompute_dx_shift = Polynomial(polys.precompute_dx.shifted());
465 polys.precompute_dy_shift = Polynomial(polys.precompute_dy.shifted());
466 polys.precompute_tx_shift = Polynomial(polys.precompute_tx.shifted());
467 polys.precompute_ty_shift = Polynomial(polys.precompute_ty.shifted());
468 polys.msm_transition_shift = Polynomial(polys.msm_transition.shifted());
469 polys.msm_add_shift = Polynomial(polys.msm_add.shifted());
470 polys.msm_double_shift = Polynomial(polys.msm_double.shifted());
471 polys.msm_skew_shift = Polynomial(polys.msm_skew.shifted());
472 polys.msm_accumulator_x_shift = Polynomial(polys.msm_accumulator_x.shifted());
473 polys.msm_accumulator_y_shift = Polynomial(polys.msm_accumulator_y.shifted());
474 polys.msm_count_shift = Polynomial(polys.msm_count.shifted());
475 polys.msm_round_shift = Polynomial(polys.msm_round.shifted());
476 polys.msm_add1_shift = Polynomial(polys.msm_add1.shifted());
477 polys.msm_pc_shift = Polynomial(polys.msm_pc.shifted());
478 polys.precompute_pc_shift = Polynomial(polys.precompute_pc.shifted());
479 polys.transcript_pc_shift = Polynomial(polys.transcript_pc.shifted());
480 polys.precompute_round_shift = Polynomial(polys.precompute_round.shifted());
481 polys.transcript_accumulator_empty_shift = Polynomial(polys.transcript_accumulator_empty.shifted());
482 polys.precompute_select_shift = Polynomial(polys.precompute_select.shifted());
488 const FF gamma = FF::random_element();
489 const FF beta = FF::random_element();
490 const FF beta_sqr = beta.sqr();
491 const FF beta_cube = beta_sqr * beta;
492 auto eccvm_set_permutation_delta =
493 gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr);
494 eccvm_set_permutation_delta = eccvm_set_permutation_delta.invert();
499 .public_input_delta = 0,
500 .lookup_grand_product_delta = 0,
501 .beta_sqr = beta_sqr,
502 .beta_cube = beta_cube,
503 .eccvm_set_permutation_delta = eccvm_set_permutation_delta,
507 const size_t num_rows = polynomials.get_polynomial_size();
508 proof_system::honk::logderivative_library::
509 compute_logderivative_inverse<Flavor, honk::sumcheck::ECCVMLookupRelation<FF>>(
510 polynomials, params, num_rows);
512 honk::permutation_library::compute_permutation_grand_product<Flavor, honk::sumcheck::ECCVMSetRelation<FF>>(
513 num_rows, polynomials, params);
515 polynomials.z_perm_shift = Polynomial(polynomials.z_perm.shifted());
517 const auto evaluate_relation = [&]<
typename Relation>(
const std::string& relation_name) {
518 typename Relation::SumcheckArrayOfValuesOverSubrelations result;
519 for (
auto& r : result) {
522 constexpr size_t NUM_SUBRELATIONS = result.size();
524 for (
size_t i = 0; i < num_rows; ++i) {
525 Relation::accumulate(result, polynomials.get_row(i), params, 1);
528 for (
size_t j = 0; j < NUM_SUBRELATIONS; ++j) {
529 if (result[j] != 0) {
530 info(
"Relation ", relation_name,
", subrelation index ", j,
" failed at row ", i);
542 result = result && evaluate_relation.template operator()<honk::sumcheck::ECCVMTranscriptRelation<FF>>(
543 "ECCVMTranscriptRelation");
544 result = result && evaluate_relation.template operator()<honk::sumcheck::ECCVMPointTableRelation<FF>>(
545 "ECCVMPointTableRelation");
547 result && evaluate_relation.template operator()<honk::sumcheck::ECCVMWnafRelation<FF>>(
"ECCVMWnafRelation");
549 result && evaluate_relation.template operator()<honk::sumcheck::ECCVMMSMRelation<FF>>(
"ECCVMMSMRelation");
551 result && evaluate_relation.template operator()<honk::sumcheck::ECCVMSetRelation<FF>>(
"ECCVMSetRelation");
553 using LookupRelation = honk::sumcheck::ECCVMLookupRelation<FF>;
554 typename honk::sumcheck::ECCVMLookupRelation<typename Flavor::FF>::SumcheckArrayOfValuesOverSubrelations
556 for (
auto& r : lookup_result) {
559 for (
size_t i = 0; i < num_rows; ++i) {
560 LookupRelation::accumulate(lookup_result, polynomials.get_row(i), params, 1);
562 for (
auto r : lookup_result) {
564 info(
"Relation ECCVMLookupRelation failed.");
571 [[nodiscard]]
size_t get_num_gates()
const
576 const auto flattened_muls = get_flattened_scalar_muls(msms);
578 std::array<std::vector<size_t>, 2> point_table_read_counts;
579 const auto transcript_state =
580 ECCVMTranscriptBuilder<Flavor>::compute_transcript_state(op_queue->raw_ops, get_number_of_muls());
581 const auto precompute_table_state =
582 ECCVMPrecomputedTablesBuilder<Flavor>::compute_precompute_state(flattened_muls);
583 const auto msm_state =
586 const size_t msm_size = msm_state.size();
587 const size_t transcript_size = transcript_state.size();
588 const size_t precompute_table_size = precompute_table_state.size();
590 const size_t num_rows = std::max(precompute_table_size, std::max(msm_size, transcript_size));
594 [[nodiscard]]
size_t get_circuit_subgroup_size(
const size_t num_rows)
const
597 const auto num_rows_log2 =
static_cast<size_t>(numeric::get_msb64(num_rows));
598 size_t num_rows_pow2 = 1UL << (num_rows_log2 + (1UL << num_rows_log2 == num_rows ? 0 : 1));
599 return num_rows_pow2;
Definition: polynomial.hpp:12
Definition: uint256.hpp:25
Definition: eccvm_circuit_builder.hpp:17
ProverPolynomials compute_polynomials()
Compute the ECCVM flavor polynomial data required to generate an ECCVM Proof.
Definition: eccvm_circuit_builder.hpp:320
std::vector< MSM > get_msms() const
Definition: eccvm_circuit_builder.hpp:66
static std::vector< MSMState > compute_msm_state(const std::vector< proof_system_eccvm::MSM< CycleGroup > > &msms, std::array< std::vector< size_t >, 2 > &point_table_read_counts, const uint32_t total_number_of_muls)
Computes the row values for the Straus MSM columns of the ECCVM.
Definition: msm_builder.hpp:56
Definition: precomputed_tables_builder.hpp:7
Definition: transcript_builder.hpp:7
A container for the prover polynomials handles.
Definition: AvmMini_flavor.hpp:263
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Definition: relation_parameters.hpp:12
Definition: eccvm_builder_types.hpp:36
Definition: eccvm_builder_types.hpp:15