3#include "barretenberg/ecc/curves/bn254/fq12.hpp"
4#include "barretenberg/ecc/curves/bn254/pairing.hpp"
5#include "barretenberg/flavor/plonk_flavors.hpp"
6#include "barretenberg/plonk/proof_system/public_inputs/public_inputs.hpp"
7#include "barretenberg/plonk/proof_system/types/proof.hpp"
8#include "barretenberg/plonk/proof_system/utils/kate_verification.hpp"
9#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp"
10#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp"
11#include "barretenberg/stdlib/primitives/bool/bool.hpp"
12#include "barretenberg/stdlib/primitives/field/field.hpp"
13#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp"
14#include "barretenberg/stdlib/recursion/transcript/transcript.hpp"
15#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp"
27template <
typename Curve,
typename Transcript,
typename program_settings>
28void populate_kate_element_map(
typename Curve::Builder* ctx,
29 typename Transcript::Key* key,
31 std::map<std::string, typename Curve::Group>& kate_g1_elements,
32 std::map<std::string, typename Curve::ScalarField>& kate_fr_elements_at_zeta,
33 std::map<std::string, typename Curve::ScalarField>& kate_fr_elements_at_zeta_large,
34 std::map<std::string, typename Curve::ScalarField>& kate_fr_elements_at_zeta_omega,
35 typename Curve::ScalarField& batch_opening_scalar)
37 using fr_ct =
typename Curve::ScalarField;
38 const auto& polynomial_manifest = key->polynomial_manifest;
39 for (
size_t i = 0; i < key->polynomial_manifest.size(); ++i) {
40 const auto& item = polynomial_manifest[i];
41 const std::string label(item.commitment_label);
42 const std::string poly_label(item.polynomial_label);
43 switch (item.source) {
44 case PolynomialSource::WITNESS: {
46 const auto element = transcript.get_circuit_group_element(label);
47 ASSERT(
element.get_value().on_curve());
48 if (
element.get_value().is_point_at_infinity()) {
49 std::cerr << label <<
" witness is point at infinity! Error!" << std::endl;
50 ctx->failure(
"witness " + label +
" is point at infinity");
52 kate_g1_elements.insert({ label,
element });
55 case PolynomialSource::SELECTOR:
56 case PolynomialSource::PERMUTATION: {
57 const auto element = key->commitments.at(label);
60 if (!element.get_value().on_curve()) {
61 std::cerr << label <<
" commitment not on curve!" << std::endl;
63 if (element.get_value().is_point_at_infinity()) {
64 std::cerr << label <<
" commitment is point at infinity! Error!" << std::endl;
65 ctx->failure(
"commitment " + label +
" is point at infinity");
67 kate_g1_elements.insert({ label, element });
70 case PolynomialSource::OTHER: {
74 if (item.requires_shifted_evaluation) {
75 const auto challenge = transcript.get_challenge_field_element_from_map(
"nu", poly_label +
"_omega");
76 kate_fr_elements_at_zeta_omega.insert({ label, challenge });
78 const auto challenge = transcript.get_challenge_field_element_from_map(
"nu", poly_label);
79 kate_fr_elements_at_zeta.insert({ label, challenge });
83 const auto zeta = transcript.get_challenge_field_element(
"z", 0);
84 const auto quotient_nu = transcript.get_challenge_field_element_from_map(
"nu",
"t");
87 for (
size_t i = 0; i < program_settings::program_width; ++i) {
88 std::string quotient_label =
"T_" + std::to_string(i + 1);
89 const auto element = transcript.get_circuit_group_element(quotient_label);
91 kate_g1_elements.insert({ quotient_label, element });
92 kate_fr_elements_at_zeta_large.insert({ quotient_label, quotient_nu * z_power });
93 z_power *= key->z_pow_n;
96 const auto PI_Z = transcript.get_circuit_group_element(
"PI_Z");
97 const auto PI_Z_OMEGA = transcript.get_circuit_group_element(
"PI_Z_OMEGA");
99 fr_ct u = transcript.get_challenge_field_element(
"separator", 0);
101 fr_ct batch_evaluation =
102 proof_system::plonk::compute_kate_batch_evaluation<fr_ct, Transcript, program_settings>(key, transcript);
103 batch_opening_scalar = -batch_evaluation;
105 kate_g1_elements.insert({
"PI_Z_OMEGA", PI_Z_OMEGA });
106 kate_fr_elements_at_zeta_large.insert({
"PI_Z_OMEGA", zeta * key->domain.root * u });
108 kate_g1_elements.insert({
"PI_Z", PI_Z });
109 kate_fr_elements_at_zeta.insert({
"PI_Z", zeta });
112template <
typename Curve>
113lagrange_evaluations<typename Curve::Builder> get_lagrange_evaluations(
114 const typename Curve::ScalarField& z,
116 const size_t num_roots_cut_out_of_vanishing_polynomial = 4)
127 typedef typename Curve::ScalarField fr_ct;
128 typedef typename Curve::Builder
Builder;
131 fr_ct numerator = z_pow - fr_ct(1);
138 fr_ct denominators_vanishing_poly = fr_ct(1);
139 lagrange_evaluations<Builder> result;
141 fr_ct work_root = domain.root_inverse;
142 for (
size_t i = 0; i < num_roots_cut_out_of_vanishing_polynomial; ++i) {
143 denominators_vanishing_poly *= (z - work_root);
144 work_root *= domain.root_inverse;
146 result.vanishing_poly = numerator / denominators_vanishing_poly;
158 numerator *= domain.domain_inverse;
160 result.l_start = numerator / (z - fr_ct(1));
163 fr_ct l_end_root = (num_roots_cut_out_of_vanishing_polynomial & 1) ? domain.root.
sqr() : domain.root;
164 for (
size_t i = 0; i < num_roots_cut_out_of_vanishing_polynomial / 2; ++i) {
165 l_end_root *= domain.root.
sqr();
167 result.l_end = numerator / ((z * l_end_root) - fr_ct(1));
176template <
typename Curve,
typename program_settings>
177aggregation_state<Curve> verify_proof(
typename Curve::Builder* context,
178 std::shared_ptr<verification_key<Curve>> key,
181 const aggregation_state<Curve> previous_output = aggregation_state<Curve>())
183 using Builder =
typename Curve::Builder;
185 key->program_width = program_settings::program_width;
187 Transcript<Builder> transcript = Transcript<Builder>(context, proof.proof_data, manifest);
189 return verify_proof_<Curve, program_settings>(context, key, transcript, previous_output);
196template <
typename Curve,
typename program_settings>
197aggregation_state<Curve> verify_proof_(
typename Curve::Builder* context,
198 std::shared_ptr<verification_key<Curve>> key,
199 Transcript<typename Curve::Builder>& transcript,
200 const aggregation_state<Curve> previous_output = aggregation_state<Curve>())
202 using fr_ct =
typename Curve::ScalarField;
203 using fq_ct =
typename Curve::BaseField;
204 using g1_ct =
typename Curve::Group;
205 using Builder =
typename Curve::Builder;
207 key->program_width = program_settings::program_width;
209 std::map<std::string, g1_ct> kate_g1_elements;
210 std::map<std::string, fr_ct> kate_fr_elements_at_zeta;
211 std::map<std::string, fr_ct> kate_fr_elements_at_zeta_large;
212 std::map<std::string, fr_ct> kate_fr_elements_at_zeta_omega;
214 const auto PI_Z = transcript.get_circuit_group_element(
"PI_Z");
215 const auto PI_Z_OMEGA = transcript.get_circuit_group_element(
"PI_Z_OMEGA");
218 field_t public_input_size = key->num_public_inputs;
220 transcript.add_field_element(
"circuit_size", circuit_size);
221 transcript.add_field_element(
"public_input_size", public_input_size);
223 transcript.apply_fiat_shamir(
"init");
224 transcript.apply_fiat_shamir(
"eta");
225 transcript.apply_fiat_shamir(
"beta");
226 transcript.apply_fiat_shamir(
"alpha");
227 transcript.apply_fiat_shamir(
"z");
229 fr_ct alpha = transcript.get_challenge_field_element(
"alpha");
230 fr_ct zeta = transcript.get_challenge_field_element(
"z");
232 key->z_pow_n = zeta.
pow(key->domain.domain);
234 lagrange_evaluations<Builder> lagrange_evals = get_lagrange_evaluations<Curve>(zeta, key->domain);
238 fr_ct quotient_numerator_eval = fr_ct(0);
239 program_settings::compute_quotient_evaluation_contribution(key.get(), alpha, transcript, quotient_numerator_eval);
241 fr_ct t_eval = quotient_numerator_eval / lagrange_evals.vanishing_poly;
242 transcript.add_field_element(
"t", t_eval);
244 transcript.apply_fiat_shamir(
"nu");
245 transcript.apply_fiat_shamir(
"separator");
247 fr_ct u = transcript.get_challenge_field_element(
"separator", 0);
249 fr_ct batch_opening_scalar;
251 populate_kate_element_map<Curve, Transcript<Builder>, program_settings>(context,
255 kate_fr_elements_at_zeta,
256 kate_fr_elements_at_zeta_large,
257 kate_fr_elements_at_zeta_omega,
258 batch_opening_scalar);
260 std::vector<fr_ct> double_opening_scalars;
261 std::vector<g1_ct> double_opening_elements;
262 std::vector<fr_ct> opening_scalars;
263 std::vector<g1_ct> opening_elements;
264 std::vector<fr_ct> big_opening_scalars;
265 std::vector<g1_ct> big_opening_elements;
266 std::vector<g1_ct> elements_to_add;
268 for (
const auto& [label, fr_value] : kate_fr_elements_at_zeta) {
269 const auto& g1_value = kate_g1_elements[label];
270 if (fr_value.get_value() == 0 && fr_value.witness_index != IS_CONSTANT) {
271 std::cerr <<
"bad scalar zero at " << label << std::endl;
273 if (fr_value.get_value() == 0 && fr_value.witness_index == IS_CONSTANT) {
274 std::cerr <<
"scalar zero at " << label << std::endl;
278 if (fr_value.get_value() == 1 && fr_value.witness_index == IS_CONSTANT) {
279 elements_to_add.emplace_back(g1_value);
282 opening_scalars.emplace_back(fr_value);
283 opening_elements.emplace_back(g1_value);
286 for (
const auto& [label, fr_value] : kate_fr_elements_at_zeta_large) {
287 const auto& g1_value = kate_g1_elements[label];
288 if (fr_value.get_value() == 0 && fr_value.witness_index != IS_CONSTANT) {
289 std::cerr <<
"bad scalar zero at " << label << std::endl;
291 if (fr_value.get_value() == 0 && fr_value.witness_index == IS_CONSTANT) {
292 std::cerr <<
"scalar zero at " << label << std::endl;
296 if (fr_value.get_value() == 1 && fr_value.witness_index == IS_CONSTANT) {
297 elements_to_add.emplace_back(g1_value);
300 big_opening_scalars.emplace_back(fr_value);
301 big_opening_elements.emplace_back(g1_value);
304 for (
const auto& [label, fr_value] : kate_fr_elements_at_zeta_omega) {
305 const auto& g1_value = kate_g1_elements[label];
306 double_opening_scalars.emplace_back(fr_value);
307 double_opening_elements.emplace_back(g1_value);
310 const auto double_opening_result = g1_ct::batch_mul(double_opening_elements, double_opening_scalars, 128);
312 opening_elements.emplace_back(double_opening_result);
313 opening_scalars.emplace_back(u);
315 std::vector<g1_ct> rhs_elements;
316 std::vector<fr_ct> rhs_scalars;
318 rhs_elements.push_back(PI_Z_OMEGA);
319 rhs_scalars.push_back(u);
321 if (previous_output.has_data) {
322 fr_ct random_separator = transcript.get_challenge_field_element(
"separator", 1);
324 opening_elements.push_back(previous_output.P0);
325 opening_scalars.push_back(random_separator);
327 rhs_elements.push_back((-(previous_output.P1)));
328 rhs_scalars.push_back(random_separator);
338 if (key->contains_recursive_proof) {
339 const auto public_inputs = transcript.get_field_element_vector(
"public_inputs");
340 const auto recover_fq_from_public_inputs =
341 [&public_inputs](
const size_t idx0,
const size_t idx1,
const size_t idx2,
const size_t idx3) {
342 const fr_ct l0 = public_inputs[idx0];
343 const fr_ct l1 = public_inputs[idx1];
344 const fr_ct l2 = public_inputs[idx2];
345 const fr_ct l3 = public_inputs[idx3];
346 l0.create_range_constraint(fq_ct::NUM_LIMB_BITS,
"l0");
347 l1.create_range_constraint(fq_ct::NUM_LIMB_BITS,
"l1");
348 l2.create_range_constraint(fq_ct::NUM_LIMB_BITS,
"l2");
349 l3.create_range_constraint(fq_ct::NUM_LAST_LIMB_BITS,
"l3");
350 return fq_ct(l0, l1, l2, l3,
false);
353 fr_ct recursion_separator_challenge = transcript.get_challenge_field_element(
"separator", 2);
355 const auto x0 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[0],
356 key->recursive_proof_public_input_indices[1],
357 key->recursive_proof_public_input_indices[2],
358 key->recursive_proof_public_input_indices[3]);
359 const auto y0 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[4],
360 key->recursive_proof_public_input_indices[5],
361 key->recursive_proof_public_input_indices[6],
362 key->recursive_proof_public_input_indices[7]);
363 const auto x1 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[8],
364 key->recursive_proof_public_input_indices[9],
365 key->recursive_proof_public_input_indices[10],
366 key->recursive_proof_public_input_indices[11]);
367 const auto y1 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[12],
368 key->recursive_proof_public_input_indices[13],
369 key->recursive_proof_public_input_indices[14],
370 key->recursive_proof_public_input_indices[15]);
372 opening_elements.push_back(g1_ct(x0, y0));
373 opening_scalars.push_back(recursion_separator_challenge);
375 rhs_elements.push_back((-g1_ct(x1, y1)));
376 rhs_scalars.push_back(recursion_separator_challenge);
379 auto opening_result = g1_ct::template bn254_endo_batch_mul_with_generator(
380 big_opening_elements, big_opening_scalars, opening_elements, opening_scalars, batch_opening_scalar, 128);
382 opening_result = opening_result + double_opening_result;
383 for (
const auto& to_add : elements_to_add) {
384 opening_result = opening_result + to_add;
387 g1_ct rhs = g1_ct::template wnaf_batch_mul<128>(rhs_elements, rhs_scalars);
392 std::vector<uint32_t> proof_witness_indices = {
393 opening_result.x.binary_basis_limbs[0].element.normalize().witness_index,
394 opening_result.x.binary_basis_limbs[1].element.normalize().witness_index,
395 opening_result.x.binary_basis_limbs[2].element.normalize().witness_index,
396 opening_result.x.binary_basis_limbs[3].element.normalize().witness_index,
397 opening_result.y.binary_basis_limbs[0].element.normalize().witness_index,
398 opening_result.y.binary_basis_limbs[1].element.normalize().witness_index,
399 opening_result.y.binary_basis_limbs[2].element.normalize().witness_index,
400 opening_result.y.binary_basis_limbs[3].element.normalize().witness_index,
401 rhs.x.binary_basis_limbs[0].element.normalize().witness_index,
402 rhs.x.binary_basis_limbs[1].element.normalize().witness_index,
403 rhs.x.binary_basis_limbs[2].element.normalize().witness_index,
404 rhs.x.binary_basis_limbs[3].element.normalize().witness_index,
405 rhs.y.binary_basis_limbs[0].element.normalize().witness_index,
406 rhs.y.binary_basis_limbs[1].element.normalize().witness_index,
407 rhs.y.binary_basis_limbs[2].element.normalize().witness_index,
408 rhs.y.binary_basis_limbs[3].element.normalize().witness_index,
410 auto result = aggregation_state<Curve>{
411 opening_result, rhs, transcript.get_field_element_vector(
"public_inputs"), proof_witness_indices,
true
416template <
typename Flavor>
417aggregation_state<bn254<typename Flavor::CircuitBuilder>> verify_proof(
418 typename Flavor::CircuitBuilder* context,
419 std::shared_ptr<verification_key<bn254<typename Flavor::CircuitBuilder>>> key,
421 const aggregation_state<bn254<typename Flavor::CircuitBuilder>> previous_output =
422 aggregation_state<bn254<typename Flavor::CircuitBuilder>>())
425 const auto manifest =
426 Flavor::create_manifest(
static_cast<size_t>(key->num_public_inputs.get_value().from_montgomery_form().data[0]));
427 return verify_proof<bn254<typename Flavor::CircuitBuilder>,
428 recursion::recursive_ultra_verifier_settings<stdlib::bn254<typename Flavor::CircuitBuilder>>>(
429 context, key, manifest, proof, previous_output);
Definition: standard_circuit_builder.hpp:12
Definition: biggroup.hpp:22
field_t pow(const field_t &exponent) const
raise a field_t to a power of an exponent (field_t). Note that the exponent must not exceed 32 bits a...
Definition: field.cpp:346
Definition: transcript.hpp:18
Definition: manifest.hpp:11
Definition: widget.bench.cpp:13
BBERG_INLINE constexpr field sqr() const noexcept
Definition: field_impl.hpp:61
Definition: verifier.hpp:21