1use crate::{
4 circuits::{
5 argument::{Argument, ArgumentType},
6 berkeley_columns::{BerkeleyChallenges, Environment, LookupEnvironment},
7 constraints::zk_rows_strict_lower_bound,
8 expr::{self, l0_1, Constants},
9 gate::GateType,
10 lookup::{self, runtime_tables::RuntimeTable, tables::combine_table_entry},
11 polynomials::{
12 complete_add::CompleteAdd,
13 endomul_scalar::EndomulScalar,
14 endosclmul::EndosclMul,
15 foreign_field_add::circuitgates::ForeignFieldAdd,
16 foreign_field_mul::{self, circuitgates::ForeignFieldMul},
17 generic, permutation,
18 poseidon::Poseidon,
19 range_check::circuitgates::{RangeCheck0, RangeCheck1},
20 rot::Rot64,
21 varbasemul::VarbaseMul,
22 xor::Xor16,
23 },
24 wires::{COLUMNS, PERMUTS},
25 },
26 curve::KimchiCurve,
27 error::ProverError,
28 lagrange_basis_evaluations::LagrangeBasisEvaluations,
29 plonk_sponge::FrSponge,
30 proof::{
31 LookupCommitments, PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof,
32 RecursionChallenge,
33 },
34 prover_index::ProverIndex,
35 verifier_index::VerifierIndex,
36};
37use ark_ff::{FftField, Field, One, PrimeField, UniformRand, Zero};
38use ark_poly::{
39 univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations, Polynomial,
40 Radix2EvaluationDomain as D,
41};
42use core::array;
43use itertools::Itertools;
44use mina_poseidon::{poseidon::ArithmeticSpongeParams, sponge::ScalarChallenge, FqSponge};
45use o1_utils::ExtendedDensePolynomial as _;
46use poly_commitment::{
47 commitment::{
48 absorb_commitment, b_poly_coefficients, BlindedCommitment, CommitmentCurve, PolyComm,
49 },
50 utils::DensePolynomialOrEvaluations,
51 OpenProof, SRS as _,
52};
53use rand_core::{CryptoRng, RngCore};
54use rayon::prelude::*;
55use std::collections::HashMap;
56
57type Result<T> = core::result::Result<T, ProverError>;
59
60macro_rules! check_constraint {
62 ($index:expr, $evaluation:expr) => {{
63 check_constraint!($index, stringify!($evaluation), $evaluation);
64 }};
65 ($index:expr, $label:expr, $evaluation:expr) => {{
66 if cfg!(debug_assertions) {
67 let (_, res) = $evaluation
68 .interpolate_by_ref()
69 .divide_by_vanishing_poly($index.cs.domain.d1);
70 if !res.is_zero() {
71 panic!("couldn't divide by vanishing polynomial: {}", $label);
72 }
73 }
74 }};
75}
76
77#[derive(Default)]
79struct LookupContext<G, F>
80where
81 G: CommitmentCurve,
82 F: FftField,
83{
84 joint_combiner: Option<F>,
86
87 table_id_combiner: Option<F>,
90
91 dummy_lookup_value: Option<F>,
93
94 joint_lookup_table: Option<DensePolynomial<F>>,
96 joint_lookup_table_d8: Option<Evaluations<F, D<F>>>,
97
98 sorted: Option<Vec<Evaluations<F, D<F>>>>,
100 sorted_coeffs: Option<Vec<DensePolynomial<F>>>,
101 sorted_comms: Option<Vec<BlindedCommitment<G>>>,
102 sorted8: Option<Vec<Evaluations<F, D<F>>>>,
103
104 aggreg_coeffs: Option<DensePolynomial<F>>,
106 aggreg_comm: Option<BlindedCommitment<G>>,
107 aggreg8: Option<Evaluations<F, D<F>>>,
108
109 pub lookup_aggregation_eval: Option<PointEvaluations<Vec<F>>>,
112 pub lookup_table_eval: Option<PointEvaluations<Vec<F>>>,
114 pub lookup_sorted_eval: [Option<PointEvaluations<Vec<F>>>; 5],
116 pub runtime_lookup_table_eval: Option<PointEvaluations<Vec<F>>>,
118
119 runtime_table: Option<DensePolynomial<F>>,
121 runtime_table_d8: Option<Evaluations<F, D<F>>>,
122 runtime_table_comm: Option<BlindedCommitment<G>>,
123 runtime_second_col_d8: Option<Evaluations<F, D<F>>>,
124}
125
126impl<G, OpeningProof, const FULL_ROUNDS: usize> ProverProof<G, OpeningProof, FULL_ROUNDS>
127where
128 G: KimchiCurve<FULL_ROUNDS>,
129 G::BaseField: PrimeField,
130 OpeningProof: OpenProof<G, FULL_ROUNDS>,
131{
132 pub fn create<EFqSponge, EFrSponge, RNG>(
138 groupmap: &G::Map,
139 witness: [Vec<G::ScalarField>; COLUMNS],
140 runtime_tables: &[RuntimeTable<G::ScalarField>],
141 index: &ProverIndex<FULL_ROUNDS, G, OpeningProof::SRS>,
142 rng: &mut RNG,
143 ) -> Result<Self>
144 where
145 EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
146 EFrSponge: FrSponge<G::ScalarField>,
147 EFrSponge: From<&'static ArithmeticSpongeParams<G::ScalarField, FULL_ROUNDS>>,
148 RNG: RngCore + CryptoRng,
149 VerifierIndex<FULL_ROUNDS, G, OpeningProof::SRS>: Clone,
150 {
151 Self::create_recursive::<EFqSponge, EFrSponge, RNG>(
152 groupmap,
153 witness,
154 runtime_tables,
155 index,
156 Vec::new(),
157 None,
158 rng,
159 )
160 }
161
162 pub fn create_recursive<EFqSponge, EFrSponge, RNG>(
174 group_map: &G::Map,
175 mut witness: [Vec<G::ScalarField>; COLUMNS],
176 runtime_tables: &[RuntimeTable<G::ScalarField>],
177 index: &ProverIndex<FULL_ROUNDS, G, OpeningProof::SRS>,
178 prev_challenges: Vec<RecursionChallenge<G>>,
179 blinders: Option<[Option<PolyComm<G::ScalarField>>; COLUMNS]>,
180 rng: &mut RNG,
181 ) -> Result<Self>
182 where
183 EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
184 EFrSponge: FrSponge<G::ScalarField>,
185 EFrSponge: From<&'static ArithmeticSpongeParams<G::ScalarField, FULL_ROUNDS>>,
186 RNG: RngCore + CryptoRng,
187 VerifierIndex<FULL_ROUNDS, G, OpeningProof::SRS>: Clone,
188 {
189 internal_tracing::checkpoint!(internal_traces; create_recursive);
190 let d1_size = index.cs.domain.d1.size();
191
192 let (_, endo_r) = G::endos();
193
194 let num_chunks = if d1_size < index.max_poly_size {
195 1
196 } else {
197 d1_size / index.max_poly_size
198 };
199
200 if cfg!(debug_assertions) && !index.cs.disable_gates_checks {
203 let public = witness[0][0..index.cs.public].to_vec();
204 index.verify(&witness, &public).expect("incorrect witness");
205 }
206
207 let length_witness = witness[0].len();
213 let length_padding = d1_size
214 .checked_sub(length_witness)
215 .ok_or(ProverError::NoRoomForZkInWitness)?;
216
217 let zero_knowledge_limit = zk_rows_strict_lower_bound(num_chunks);
218 if (index.cs.zk_rows as usize) <= zero_knowledge_limit {
227 return Err(ProverError::NotZeroKnowledge(
228 zero_knowledge_limit + 1,
229 index.cs.zk_rows as usize,
230 ));
231 }
232
233 if length_padding < index.cs.zk_rows as usize {
234 return Err(ProverError::NoRoomForZkInWitness);
235 }
236
237 internal_tracing::checkpoint!(internal_traces; pad_witness);
240 for w in &mut witness {
241 if w.len() != length_witness {
242 return Err(ProverError::WitnessCsInconsistent);
243 }
244
245 w.extend(std::iter::repeat_n(G::ScalarField::zero(), length_padding));
247
248 for row in w.iter_mut().rev().take(index.cs.zk_rows as usize) {
250 *row = <G::ScalarField as UniformRand>::rand(rng);
251 }
252 }
253
254 internal_tracing::checkpoint!(internal_traces; set_up_fq_sponge);
256 let mut fq_sponge = EFqSponge::new(G::other_curve_sponge_params());
257
258 let verifier_index_digest = index.verifier_index_digest::<EFqSponge>();
260 fq_sponge.absorb_fq(&[verifier_index_digest]);
261
262 for RecursionChallenge { comm, .. } in &prev_challenges {
264 absorb_commitment(&mut fq_sponge, comm)
265 }
266
267 let public = witness[0][0..index.cs.public].to_vec();
271 let public_poly = -Evaluations::<G::ScalarField, D<G::ScalarField>>::from_vec_and_domain(
272 public,
273 index.cs.domain.d1,
274 )
275 .interpolate();
276
277 let public_comm = index.srs.commit_non_hiding(&public_poly, num_chunks);
279 let public_comm = {
280 index
281 .srs
282 .mask_custom(
283 public_comm.clone(),
284 &public_comm.map(|_| G::ScalarField::one()),
285 )
286 .unwrap()
287 .commitment
288 };
289
290 absorb_commitment(&mut fq_sponge, &public_comm);
296
297 internal_tracing::checkpoint!(internal_traces; commit_to_witness_columns);
302 let blinders_final: Vec<PolyComm<G::ScalarField>> = match blinders {
304 None => (0..COLUMNS)
305 .map(|_| PolyComm::new(vec![UniformRand::rand(rng); num_chunks]))
306 .collect(),
307 Some(blinders_arr) => blinders_arr
308 .into_iter()
309 .map(|blinder_el| match blinder_el {
310 None => PolyComm::new(vec![UniformRand::rand(rng); num_chunks]),
311 Some(blinder_el_some) => blinder_el_some,
312 })
313 .collect(),
314 };
315 let w_comm_opt_res: Vec<Result<_>> = witness
316 .clone()
317 .into_par_iter()
318 .zip(blinders_final.into_par_iter())
319 .map(|(witness, blinder)| {
320 let witness_eval =
321 Evaluations::<G::ScalarField, D<G::ScalarField>>::from_vec_and_domain(
322 witness,
323 index.cs.domain.d1,
324 );
325
326 let witness_com = index
328 .srs
329 .commit_evaluations_non_hiding(index.cs.domain.d1, &witness_eval);
330 let com = index
331 .srs
332 .mask_custom(witness_com, &blinder)
333 .map_err(ProverError::WrongBlinders)?;
334
335 Ok(com)
336 })
337 .collect();
338
339 let w_comm_res: Result<Vec<BlindedCommitment<G>>> = w_comm_opt_res.into_iter().collect();
340
341 let w_comm = w_comm_res?;
342
343 let w_comm: [BlindedCommitment<G>; COLUMNS] = w_comm
344 .try_into()
345 .expect("previous loop is of the correct length");
346
347 w_comm
349 .iter()
350 .for_each(|c| absorb_commitment(&mut fq_sponge, &c.commitment));
351
352 let witness_poly: [DensePolynomial<G::ScalarField>; COLUMNS] = (0..COLUMNS)
357 .into_par_iter()
358 .map(|i| {
359 Evaluations::<G::ScalarField, D<G::ScalarField>>::from_vec_and_domain(
360 witness[i].clone(),
361 index.cs.domain.d1,
362 )
363 .interpolate()
364 })
365 .collect::<Vec<_>>()
366 .try_into()
367 .unwrap();
368
369 let mut lookup_context = LookupContext::default();
370
371 let lookup_constraint_system = index
373 .cs
374 .lookup_constraint_system
375 .try_get_or_err()
376 .map_err(ProverError::from)?;
377 if let Some(lcs) = lookup_constraint_system {
378 internal_tracing::checkpoint!(internal_traces; use_lookup, {
379 "uses_lookup": true,
380 "uses_runtime_tables": lcs.runtime_tables.is_some(),
381 });
382 if let Some(cfg_runtime_tables) = &lcs.runtime_tables {
384 let expected_runtime: Vec<_> = cfg_runtime_tables
387 .iter()
388 .map(|rt| (rt.id, rt.len))
389 .collect();
390 let runtime: Vec<_> = runtime_tables
391 .iter()
392 .map(|rt| (rt.id, rt.data.len()))
393 .collect();
394 if expected_runtime != runtime {
395 return Err(ProverError::RuntimeTablesInconsistent);
396 }
397
398 let (runtime_table_contribution, runtime_table_contribution_d8) = {
401 let mut offset = lcs
402 .runtime_table_offset
403 .expect("runtime configuration missing offset");
404
405 let mut evals = vec![G::ScalarField::zero(); d1_size];
406 for rt in runtime_tables {
407 let range = offset..(offset + rt.data.len());
408 evals[range].copy_from_slice(&rt.data);
409 offset += rt.data.len();
410 }
411
412 for e in evals.iter_mut().rev().take(index.cs.zk_rows as usize) {
414 *e = <G::ScalarField as UniformRand>::rand(rng);
415 }
416
417 let runtime_table_contribution =
419 Evaluations::from_vec_and_domain(evals, index.cs.domain.d1).interpolate();
420
421 let runtime_table_contribution_d8 =
422 runtime_table_contribution.evaluate_over_domain_by_ref(index.cs.domain.d8);
423
424 (runtime_table_contribution, runtime_table_contribution_d8)
425 };
426
427 let runtime_table_comm =
430 index
431 .srs
432 .commit(&runtime_table_contribution, num_chunks, rng);
433
434 absorb_commitment(&mut fq_sponge, &runtime_table_comm.commitment);
436
437 let mut second_column_d8 = runtime_table_contribution_d8.clone();
439 second_column_d8
440 .evals
441 .par_iter_mut()
442 .enumerate()
443 .for_each(|(row, e)| {
444 *e += lcs.lookup_table8[1][row];
445 });
446
447 lookup_context.runtime_table = Some(runtime_table_contribution);
448 lookup_context.runtime_table_d8 = Some(runtime_table_contribution_d8);
449 lookup_context.runtime_table_comm = Some(runtime_table_comm);
450 lookup_context.runtime_second_col_d8 = Some(second_column_d8);
451 }
452
453 let joint_combiner = if lcs.configuration.lookup_info.features.joint_lookup_used {
457 fq_sponge.challenge()
458 } else {
459 G::ScalarField::zero()
460 };
461
462 let joint_combiner: G::ScalarField = ScalarChallenge(joint_combiner).to_field(endo_r);
464
465 let table_id_combiner: G::ScalarField = if lcs.table_ids8.as_ref().is_some() {
469 joint_combiner.pow([lcs.configuration.lookup_info.max_joint_size as u64])
470 } else {
471 G::ScalarField::zero()
473 };
474 lookup_context.table_id_combiner = Some(table_id_combiner);
475
476 let dummy_lookup_value = lcs
479 .configuration
480 .dummy_lookup
481 .evaluate(&joint_combiner, &table_id_combiner);
482 lookup_context.dummy_lookup_value = Some(dummy_lookup_value);
483
484 let joint_lookup_table_d8 = {
486 let mut evals = Vec::with_capacity(d1_size);
487
488 for idx in 0..(d1_size * 8) {
489 let table_id = match lcs.table_ids8.as_ref() {
490 Some(table_ids8) => table_ids8.evals[idx],
491 None =>
492 {
495 G::ScalarField::zero()
496 }
497 };
498
499 let combined_entry =
500 if !lcs.configuration.lookup_info.features.uses_runtime_tables {
501 let table_row = lcs.lookup_table8.iter().map(|e| &e.evals[idx]);
502
503 combine_table_entry(
504 &joint_combiner,
505 &table_id_combiner,
506 table_row,
507 &table_id,
508 )
509 } else {
510 let second_col = lookup_context.runtime_second_col_d8.as_ref().unwrap();
512
513 let table_row = lcs.lookup_table8.iter().enumerate().map(|(col, e)| {
514 if col == 1 {
515 &second_col.evals[idx]
516 } else {
517 &e.evals[idx]
518 }
519 });
520
521 combine_table_entry(
522 &joint_combiner,
523 &table_id_combiner,
524 table_row,
525 &table_id,
526 )
527 };
528 evals.push(combined_entry);
529 }
530
531 Evaluations::from_vec_and_domain(evals, index.cs.domain.d8)
532 };
533
534 let joint_lookup_table = joint_lookup_table_d8.interpolate_by_ref();
536
537 let sorted: Vec<_> = lookup::constraints::sorted(
542 dummy_lookup_value,
543 &joint_lookup_table_d8,
544 index.cs.domain.d1,
545 &index.cs.gates,
546 &witness,
547 joint_combiner,
548 table_id_combiner,
549 &lcs.configuration.lookup_info,
550 index.cs.zk_rows as usize,
551 )?;
552
553 let sorted: Vec<_> = sorted
556 .into_iter()
557 .map(|chunk| {
558 lookup::constraints::zk_patch(
559 chunk,
560 index.cs.domain.d1,
561 index.cs.zk_rows as usize,
562 rng,
563 )
564 })
565 .collect();
566
567 let sorted_comms: Vec<_> = sorted
569 .iter()
570 .map(|v| index.srs.commit_evaluations(index.cs.domain.d1, v, rng))
571 .collect();
572
573 sorted_comms
575 .iter()
576 .for_each(|c| absorb_commitment(&mut fq_sponge, &c.commitment));
577
578 let sorted_coeffs: Vec<_> = sorted.iter().map(|e| e.clone().interpolate()).collect();
581 let sorted8: Vec<_> = sorted_coeffs
582 .iter()
583 .map(|v| v.evaluate_over_domain_by_ref(index.cs.domain.d8))
584 .collect();
585
586 lookup_context.joint_combiner = Some(joint_combiner);
587 lookup_context.sorted = Some(sorted);
588 lookup_context.sorted_coeffs = Some(sorted_coeffs);
589 lookup_context.sorted_comms = Some(sorted_comms);
590 lookup_context.sorted8 = Some(sorted8);
591 lookup_context.joint_lookup_table_d8 = Some(joint_lookup_table_d8);
592 lookup_context.joint_lookup_table = Some(joint_lookup_table);
593 }
594
595 let beta = fq_sponge.challenge();
597
598 let gamma = fq_sponge.challenge();
600
601 if let Some(lcs) = lookup_constraint_system {
603 let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap();
605
606 let aggreg = lookup::constraints::aggregation::<_, G::ScalarField>(
607 lookup_context.dummy_lookup_value.unwrap(),
608 joint_lookup_table_d8,
609 index.cs.domain.d1,
610 &index.cs.gates,
611 &witness,
612 &lookup_context.joint_combiner.unwrap(),
613 &lookup_context.table_id_combiner.unwrap(),
614 beta,
615 gamma,
616 lookup_context.sorted.as_ref().unwrap(),
617 rng,
618 &lcs.configuration.lookup_info,
619 index.cs.zk_rows as usize,
620 )?;
621
622 let aggreg_comm = index
624 .srs
625 .commit_evaluations(index.cs.domain.d1, &aggreg, rng);
626
627 absorb_commitment(&mut fq_sponge, &aggreg_comm.commitment);
629
630 let aggreg_coeffs = aggreg.interpolate();
632 let aggreg8 = aggreg_coeffs.evaluate_over_domain_by_ref(index.cs.domain.d8);
635
636 lookup_context.aggreg_comm = Some(aggreg_comm);
637 lookup_context.aggreg_coeffs = Some(aggreg_coeffs);
638 lookup_context.aggreg8 = Some(aggreg8);
639 }
640
641 let column_evaluations = index.column_evaluations.get();
642
643 internal_tracing::checkpoint!(internal_traces; z_permutation_aggregation_polynomial);
645 let z_poly = index.perm_aggreg(&witness, &beta, &gamma, rng)?;
646
647 let z_comm = index.srs.commit(&z_poly, num_chunks, rng);
649
650 absorb_commitment(&mut fq_sponge, &z_comm.commitment);
652
653 let alpha_chal = ScalarChallenge(fq_sponge.challenge());
655
656 let alpha: G::ScalarField = alpha_chal.to_field(endo_r);
658
659 let mut all_alphas = index.powers_of_alpha.clone();
661 all_alphas.instantiate(alpha);
662
663 let lookup_env = if let Some(lcs) = lookup_constraint_system {
672 let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap();
673
674 Some(LookupEnvironment {
675 aggreg: lookup_context.aggreg8.as_ref().unwrap(),
676 sorted: lookup_context.sorted8.as_ref().unwrap(),
677 selectors: &lcs.lookup_selectors,
678 table: joint_lookup_table_d8,
679 runtime_selector: lcs.runtime_selector.as_ref(),
680 runtime_table: lookup_context.runtime_table_d8.as_ref(),
681 })
682 } else {
683 None
684 };
685
686 internal_tracing::checkpoint!(internal_traces; eval_witness_polynomials_over_domains);
687 let lagrange = index.cs.evaluate(&witness_poly, &z_poly);
688 internal_tracing::checkpoint!(internal_traces; compute_index_evals);
689 let env = {
690 let mut index_evals = HashMap::new();
691 use GateType::*;
692 index_evals.insert(Generic, &column_evaluations.generic_selector4);
693 index_evals.insert(Poseidon, &column_evaluations.poseidon_selector8);
694 index_evals.insert(CompleteAdd, &column_evaluations.complete_add_selector4);
695 index_evals.insert(VarBaseMul, &column_evaluations.mul_selector8);
696 index_evals.insert(EndoMul, &column_evaluations.emul_selector8);
697 index_evals.insert(EndoMulScalar, &column_evaluations.endomul_scalar_selector8);
698
699 if let Some(selector) = &column_evaluations.range_check0_selector8 {
700 index_evals.insert(GateType::RangeCheck0, selector);
701 }
702
703 if let Some(selector) = &column_evaluations.range_check1_selector8 {
704 index_evals.insert(GateType::RangeCheck1, selector);
705 }
706
707 if let Some(selector) = &column_evaluations.foreign_field_add_selector8 {
708 index_evals.insert(GateType::ForeignFieldAdd, selector);
709 }
710
711 if let Some(selector) = &column_evaluations.foreign_field_mul_selector8 {
712 index_evals.extend(
713 foreign_field_mul::gadget::circuit_gates()
714 .iter()
715 .map(|gate_type| (*gate_type, selector)),
716 );
717 }
718
719 if let Some(selector) = &column_evaluations.xor_selector8 {
720 index_evals.insert(GateType::Xor16, selector);
721 }
722
723 if let Some(selector) = &column_evaluations.rot_selector8 {
724 index_evals.insert(GateType::Rot64, selector);
725 }
726
727 let mds = &G::sponge_params().mds;
728 Environment {
729 constants: Constants {
730 endo_coefficient: index.cs.endo,
731 mds,
732 zk_rows: index.cs.zk_rows,
733 },
734 challenges: BerkeleyChallenges {
735 alpha,
736 beta,
737 gamma,
738 joint_combiner: lookup_context
739 .joint_combiner
740 .unwrap_or(G::ScalarField::zero()),
741 },
742 witness: &lagrange.d8.this.w,
743 coefficient: &column_evaluations.coefficients8,
744 vanishes_on_zero_knowledge_and_previous_rows: &index
745 .cs
746 .precomputations()
747 .vanishes_on_zero_knowledge_and_previous_rows,
748 z: &lagrange.d8.this.z,
749 l0_1: l0_1(index.cs.domain.d1),
750 domain: index.cs.domain,
751 index: index_evals,
752 lookup: lookup_env,
753 }
754 };
755
756 let mut cache = expr::Cache::default();
757
758 internal_tracing::checkpoint!(internal_traces; compute_quotient_poly);
759
760 let quotient_poly = {
761 let mut t4 = {
763 let generic_constraint =
764 generic::Generic::combined_constraints(&all_alphas, &mut cache);
765 let generic4 = generic_constraint.evaluations(&env);
766
767 if cfg!(debug_assertions) {
768 let p4 = public_poly.evaluate_over_domain_by_ref(index.cs.domain.d4);
769 let gen_minus_pub = &generic4 + &p4;
770
771 check_constraint!(index, gen_minus_pub);
772 }
773
774 generic4
775 };
776
777 let (mut t8, bnd) = {
779 let alphas =
780 all_alphas.get_alphas(ArgumentType::Permutation, permutation::CONSTRAINTS);
781 let (perm, bnd) = index.perm_quot(&lagrange, beta, gamma, &z_poly, alphas)?;
782
783 check_constraint!(index, perm);
784
785 (perm, bnd)
786 };
787
788 {
789 use crate::circuits::argument::DynArgument;
790
791 let range_check0_enabled = column_evaluations.range_check0_selector8.is_some();
792 let range_check1_enabled = column_evaluations.range_check1_selector8.is_some();
793 let foreign_field_addition_enabled =
794 column_evaluations.foreign_field_add_selector8.is_some();
795 let foreign_field_multiplication_enabled =
796 column_evaluations.foreign_field_mul_selector8.is_some();
797 let xor_enabled = column_evaluations.xor_selector8.is_some();
798 let rot_enabled = column_evaluations.rot_selector8.is_some();
799
800 for gate in [
801 (
802 (&CompleteAdd::default() as &dyn DynArgument<G::ScalarField>),
803 true,
804 ),
805 (&VarbaseMul::default(), true),
806 (&EndosclMul::default(), true),
807 (&EndomulScalar::default(), true),
808 (&Poseidon::default(), true),
809 (&RangeCheck0::default(), range_check0_enabled),
811 (&RangeCheck1::default(), range_check1_enabled),
812 (&ForeignFieldAdd::default(), foreign_field_addition_enabled),
814 (
816 &ForeignFieldMul::default(),
817 foreign_field_multiplication_enabled,
818 ),
819 (&Xor16::default(), xor_enabled),
821 (&Rot64::default(), rot_enabled),
823 ]
824 .into_iter()
825 .filter_map(|(gate, is_enabled)| if is_enabled { Some(gate) } else { None })
826 {
827 let constraint = gate.combined_constraints(&all_alphas, &mut cache);
828 let eval = constraint.evaluations(&env);
829 if eval.domain().size == t4.domain().size {
830 t4 += &eval;
831 } else if eval.domain().size == t8.domain().size {
832 t8 += &eval;
833 } else {
834 panic!("Bad evaluation")
835 }
836 check_constraint!(index, format!("{:?}", gate.argument_type()), eval);
837 }
838 };
839
840 {
842 if let Some(lcs) = lookup_constraint_system {
843 let constraints = lookup::constraints::constraints(&lcs.configuration, false);
844 let constraints_len = u32::try_from(constraints.len())
845 .expect("not expecting a large amount of constraints");
846 let lookup_alphas =
847 all_alphas.get_alphas(ArgumentType::Lookup, constraints_len);
848
849 for (ii, (constraint, alpha_pow)) in
852 constraints.into_iter().zip_eq(lookup_alphas).enumerate()
853 {
854 let mut eval = constraint.evaluations(&env);
855 eval.evals.par_iter_mut().for_each(|x| *x *= alpha_pow);
856
857 if eval.domain().size == t4.domain().size {
858 t4 += &eval;
859 } else if eval.domain().size == t8.domain().size {
860 t8 += &eval;
861 } else if eval.evals.iter().all(|x| x.is_zero()) {
862 } else {
864 panic!("Bad evaluation")
865 }
866
867 check_constraint!(index, format!("lookup constraint #{ii}"), eval);
868 }
869 }
870 }
871
872 let mut f = t4.interpolate() + t8.interpolate();
874 f += &public_poly;
875
876 let (mut quotient, res) = f.divide_by_vanishing_poly(index.cs.domain.d1);
878 if !res.is_zero() {
879 return Err(ProverError::Prover(
880 "rest of division by vanishing polynomial",
881 ));
882 }
883
884 quotient += &bnd; quotient
886 };
887
888 let t_comm = { index.srs.commit("ient_poly, 7 * num_chunks, rng) };
890
891 absorb_commitment(&mut fq_sponge, &t_comm.commitment);
893
894 let zeta_chal = ScalarChallenge(fq_sponge.challenge());
896
897 let zeta = zeta_chal.to_field(endo_r);
899
900 let omega = index.cs.domain.d1.group_gen;
901 let zeta_omega = zeta * omega;
902
903 if lookup_constraint_system.is_some() {
905 let aggreg = lookup_context
907 .aggreg_coeffs
908 .as_ref()
909 .unwrap()
910 .to_chunked_polynomial(num_chunks, index.max_poly_size);
911
912 let sorted = lookup_context
914 .sorted_coeffs
915 .as_ref()
916 .unwrap()
917 .iter()
918 .map(|c| c.to_chunked_polynomial(num_chunks, index.max_poly_size))
919 .collect::<Vec<_>>();
920
921 let joint_table = lookup_context.joint_lookup_table.as_ref().unwrap();
923 let joint_table = joint_table.to_chunked_polynomial(num_chunks, index.max_poly_size);
924
925 lookup_context.lookup_aggregation_eval = Some(PointEvaluations {
926 zeta: aggreg.evaluate_chunks(zeta),
927 zeta_omega: aggreg.evaluate_chunks(zeta_omega),
928 });
929 lookup_context.lookup_table_eval = Some(PointEvaluations {
930 zeta: joint_table.evaluate_chunks(zeta),
931 zeta_omega: joint_table.evaluate_chunks(zeta_omega),
932 });
933 lookup_context.lookup_sorted_eval = array::from_fn(|i| {
934 if i < sorted.len() {
935 let sorted = &sorted[i];
936 Some(PointEvaluations {
937 zeta: sorted.evaluate_chunks(zeta),
938 zeta_omega: sorted.evaluate_chunks(zeta_omega),
939 })
940 } else {
941 None
942 }
943 });
944 lookup_context.runtime_lookup_table_eval =
945 lookup_context.runtime_table.as_ref().map(|runtime_table| {
946 let runtime_table =
947 runtime_table.to_chunked_polynomial(num_chunks, index.max_poly_size);
948 PointEvaluations {
949 zeta: runtime_table.evaluate_chunks(zeta),
950 zeta_omega: runtime_table.evaluate_chunks(zeta_omega),
951 }
952 });
953 }
954
955 internal_tracing::checkpoint!(internal_traces; lagrange_basis_eval_zeta_poly);
975 let zeta_evals =
976 LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta);
977 internal_tracing::checkpoint!(internal_traces; lagrange_basis_eval_zeta_omega_poly);
978 let zeta_omega_evals =
979 LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta_omega);
980
981 let chunked_evals_for_selector =
982 |p: &Evaluations<G::ScalarField, D<G::ScalarField>>| PointEvaluations {
983 zeta: zeta_evals.evaluate_boolean(p),
984 zeta_omega: zeta_omega_evals.evaluate_boolean(p),
985 };
986
987 let chunked_evals_for_evaluations =
988 |p: &Evaluations<G::ScalarField, D<G::ScalarField>>| PointEvaluations {
989 zeta: zeta_evals.evaluate(p),
990 zeta_omega: zeta_omega_evals.evaluate(p),
991 };
992
993 internal_tracing::checkpoint!(internal_traces; chunk_eval_zeta_omega_poly);
994 let chunked_evals = ProofEvaluations::<PointEvaluations<Vec<G::ScalarField>>> {
995 public: {
996 let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size);
997 Some(PointEvaluations {
998 zeta: chunked.evaluate_chunks(zeta),
999 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1000 })
1001 },
1002 s: array::from_fn(|i| {
1003 chunked_evals_for_evaluations(&column_evaluations.permutation_coefficients8[i])
1004 }),
1005 coefficients: array::from_fn(|i| {
1006 chunked_evals_for_evaluations(&column_evaluations.coefficients8[i])
1007 }),
1008 w: array::from_fn(|i| {
1009 let chunked =
1010 witness_poly[i].to_chunked_polynomial(num_chunks, index.max_poly_size);
1011 PointEvaluations {
1012 zeta: chunked.evaluate_chunks(zeta),
1013 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1014 }
1015 }),
1016
1017 z: {
1018 let chunked = z_poly.to_chunked_polynomial(num_chunks, index.max_poly_size);
1019 PointEvaluations {
1020 zeta: chunked.evaluate_chunks(zeta),
1021 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1022 }
1023 },
1024
1025 lookup_aggregation: lookup_context.lookup_aggregation_eval.take(),
1026 lookup_table: lookup_context.lookup_table_eval.take(),
1027 lookup_sorted: array::from_fn(|i| lookup_context.lookup_sorted_eval[i].take()),
1028 runtime_lookup_table: lookup_context.runtime_lookup_table_eval.take(),
1029 generic_selector: chunked_evals_for_selector(&column_evaluations.generic_selector4),
1030 poseidon_selector: chunked_evals_for_selector(&column_evaluations.poseidon_selector8),
1031 complete_add_selector: chunked_evals_for_selector(
1032 &column_evaluations.complete_add_selector4,
1033 ),
1034 mul_selector: chunked_evals_for_selector(&column_evaluations.mul_selector8),
1035 emul_selector: chunked_evals_for_selector(&column_evaluations.emul_selector8),
1036 endomul_scalar_selector: chunked_evals_for_selector(
1037 &column_evaluations.endomul_scalar_selector8,
1038 ),
1039
1040 range_check0_selector: column_evaluations
1041 .range_check0_selector8
1042 .as_ref()
1043 .map(chunked_evals_for_selector),
1044 range_check1_selector: column_evaluations
1045 .range_check1_selector8
1046 .as_ref()
1047 .map(chunked_evals_for_selector),
1048 foreign_field_add_selector: column_evaluations
1049 .foreign_field_add_selector8
1050 .as_ref()
1051 .map(chunked_evals_for_selector),
1052 foreign_field_mul_selector: column_evaluations
1053 .foreign_field_mul_selector8
1054 .as_ref()
1055 .map(chunked_evals_for_selector),
1056 xor_selector: column_evaluations
1057 .xor_selector8
1058 .as_ref()
1059 .map(chunked_evals_for_selector),
1060 rot_selector: column_evaluations
1061 .rot_selector8
1062 .as_ref()
1063 .map(chunked_evals_for_selector),
1064
1065 runtime_lookup_table_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1066 lcs.runtime_selector
1067 .as_ref()
1068 .map(chunked_evals_for_selector)
1069 }),
1070 xor_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1071 lcs.lookup_selectors
1072 .xor
1073 .as_ref()
1074 .map(chunked_evals_for_selector)
1075 }),
1076 lookup_gate_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1077 lcs.lookup_selectors
1078 .lookup
1079 .as_ref()
1080 .map(chunked_evals_for_selector)
1081 }),
1082 range_check_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1083 lcs.lookup_selectors
1084 .range_check
1085 .as_ref()
1086 .map(chunked_evals_for_selector)
1087 }),
1088 foreign_field_mul_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1089 lcs.lookup_selectors
1090 .ffmul
1091 .as_ref()
1092 .map(chunked_evals_for_selector)
1093 }),
1094 };
1095
1096 let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]);
1097 let zeta_omega_to_srs_len = zeta_omega.pow([index.max_poly_size as u64]);
1098 let zeta_to_domain_size = zeta.pow([d1_size as u64]);
1099
1100 let evals: ProofEvaluations<PointEvaluations<G::ScalarField>> = {
1103 let powers_of_eval_points_for_chunks = PointEvaluations {
1104 zeta: zeta_to_srs_len,
1105 zeta_omega: zeta_omega_to_srs_len,
1106 };
1107 chunked_evals.combine(&powers_of_eval_points_for_chunks)
1108 };
1109
1110 internal_tracing::checkpoint!(internal_traces; compute_ft_poly);
1113 let ft: DensePolynomial<G::ScalarField> = {
1114 let f_chunked = {
1115 let alphas =
1121 all_alphas.get_alphas(ArgumentType::Permutation, permutation::CONSTRAINTS);
1122 let f = index.perm_lnrz(&evals, zeta, beta, gamma, alphas);
1123
1124 let f = {
1126 let (_lin_constant, mut lin) =
1127 index.linearization.to_polynomial(&env, zeta, &evals);
1128 lin += &f;
1129 lin.interpolate()
1130 };
1131
1132 drop(env);
1133
1134 f.to_chunked_polynomial(num_chunks, index.max_poly_size)
1136 .linearize(zeta_to_srs_len)
1137 };
1138
1139 let t_chunked = quotient_poly
1140 .to_chunked_polynomial(7 * num_chunks, index.max_poly_size)
1141 .linearize(zeta_to_srs_len);
1142
1143 &f_chunked - &t_chunked.scale(zeta_to_domain_size - G::ScalarField::one())
1144 };
1145
1146 let blinding_ft = {
1149 let blinding_t = t_comm.blinders.chunk_blinding(zeta_to_srs_len);
1150 let blinding_f = G::ScalarField::zero();
1151
1152 PolyComm {
1153 chunks: vec![
1155 blinding_f - (zeta_to_domain_size - G::ScalarField::one()) * blinding_t,
1156 ],
1157 }
1158 };
1159
1160 internal_tracing::checkpoint!(internal_traces; ft_eval_zeta_omega);
1162 let ft_eval1 = ft.evaluate(&zeta_omega);
1163
1164 let fq_sponge_before_evaluations = fq_sponge.clone();
1166 let mut fr_sponge = EFrSponge::from(G::sponge_params());
1167
1168 fr_sponge.absorb(&fq_sponge.digest());
1170
1171 let prev_challenge_digest = {
1173 let mut fr_sponge = EFrSponge::from(G::sponge_params());
1176 for RecursionChallenge { chals, .. } in &prev_challenges {
1177 fr_sponge.absorb_multiple(chals);
1178 }
1179 fr_sponge.digest()
1180 };
1181 fr_sponge.absorb(&prev_challenge_digest);
1182
1183 internal_tracing::checkpoint!(internal_traces; build_polynomials);
1185 let polys = prev_challenges
1186 .iter()
1187 .map(|RecursionChallenge { chals, comm }| {
1188 (
1189 DensePolynomial::from_coefficients_vec(b_poly_coefficients(chals)),
1190 comm.len(),
1191 )
1192 })
1193 .collect::<Vec<_>>();
1194
1195 fr_sponge.absorb(&ft_eval1);
1197
1198 fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta);
1206 fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta_omega);
1207 fr_sponge.absorb_evaluations(&chunked_evals);
1208
1209 let v_chal = fr_sponge.challenge();
1211
1212 let v = v_chal.to_field(endo_r);
1214
1215 let u_chal = fr_sponge.challenge();
1217
1218 let u = u_chal.to_field(endo_r);
1220
1221 let non_hiding = |n_chunks: usize| PolyComm {
1225 chunks: vec![G::ScalarField::zero(); n_chunks],
1226 };
1227
1228 let fixed_hiding = |n_chunks: usize| PolyComm {
1229 chunks: vec![G::ScalarField::one(); n_chunks],
1230 };
1231
1232 let coefficients_form = DensePolynomialOrEvaluations::DensePolynomial;
1233 let evaluations_form = |e| DensePolynomialOrEvaluations::Evaluations(e, index.cs.domain.d1);
1234
1235 let mut polynomials = polys
1236 .iter()
1237 .map(|(p, n_chunks)| (coefficients_form(p), non_hiding(*n_chunks)))
1238 .collect::<Vec<_>>();
1239
1240 polynomials.push((coefficients_form(&public_poly), fixed_hiding(num_chunks)));
1249 polynomials.push((coefficients_form(&ft), blinding_ft));
1250 polynomials.push((coefficients_form(&z_poly), z_comm.blinders));
1251 polynomials.push((
1252 evaluations_form(&column_evaluations.generic_selector4),
1253 fixed_hiding(num_chunks),
1254 ));
1255 polynomials.push((
1256 evaluations_form(&column_evaluations.poseidon_selector8),
1257 fixed_hiding(num_chunks),
1258 ));
1259 polynomials.push((
1260 evaluations_form(&column_evaluations.complete_add_selector4),
1261 fixed_hiding(num_chunks),
1262 ));
1263 polynomials.push((
1264 evaluations_form(&column_evaluations.mul_selector8),
1265 fixed_hiding(num_chunks),
1266 ));
1267 polynomials.push((
1268 evaluations_form(&column_evaluations.emul_selector8),
1269 fixed_hiding(num_chunks),
1270 ));
1271 polynomials.push((
1272 evaluations_form(&column_evaluations.endomul_scalar_selector8),
1273 fixed_hiding(num_chunks),
1274 ));
1275 polynomials.extend(
1276 witness_poly
1277 .iter()
1278 .zip(w_comm.iter())
1279 .map(|(w, c)| (coefficients_form(w), c.blinders.clone()))
1280 .collect::<Vec<_>>(),
1281 );
1282 polynomials.extend(
1283 column_evaluations
1284 .coefficients8
1285 .iter()
1286 .map(|coefficientm| (evaluations_form(coefficientm), non_hiding(num_chunks)))
1287 .collect::<Vec<_>>(),
1288 );
1289 polynomials.extend(
1290 column_evaluations.permutation_coefficients8[0..PERMUTS - 1]
1291 .iter()
1292 .map(|w| (evaluations_form(w), non_hiding(num_chunks)))
1293 .collect::<Vec<_>>(),
1294 );
1295
1296 if let Some(range_check0_selector8) = &column_evaluations.range_check0_selector8 {
1298 polynomials.push((
1299 evaluations_form(range_check0_selector8),
1300 non_hiding(num_chunks),
1301 ));
1302 }
1303 if let Some(range_check1_selector8) = &column_evaluations.range_check1_selector8 {
1304 polynomials.push((
1305 evaluations_form(range_check1_selector8),
1306 non_hiding(num_chunks),
1307 ));
1308 }
1309 if let Some(foreign_field_add_selector8) = &column_evaluations.foreign_field_add_selector8 {
1310 polynomials.push((
1311 evaluations_form(foreign_field_add_selector8),
1312 non_hiding(num_chunks),
1313 ));
1314 }
1315 if let Some(foreign_field_mul_selector8) = &column_evaluations.foreign_field_mul_selector8 {
1316 polynomials.push((
1317 evaluations_form(foreign_field_mul_selector8),
1318 non_hiding(num_chunks),
1319 ));
1320 }
1321 if let Some(xor_selector8) = &column_evaluations.xor_selector8 {
1322 polynomials.push((evaluations_form(xor_selector8), non_hiding(num_chunks)));
1323 }
1324 if let Some(rot_selector8) = &column_evaluations.rot_selector8 {
1325 polynomials.push((evaluations_form(rot_selector8), non_hiding(num_chunks)));
1326 }
1327
1328 if let Some(lcs) = lookup_constraint_system {
1331 let sorted_poly = lookup_context.sorted_coeffs.as_ref().unwrap();
1333 let sorted_comms = lookup_context.sorted_comms.as_ref().unwrap();
1334
1335 for (poly, comm) in sorted_poly.iter().zip(sorted_comms) {
1336 polynomials.push((coefficients_form(poly), comm.blinders.clone()));
1337 }
1338
1339 let aggreg_poly = lookup_context.aggreg_coeffs.as_ref().unwrap();
1341 let aggreg_comm = lookup_context.aggreg_comm.as_ref().unwrap();
1342 polynomials.push((coefficients_form(aggreg_poly), aggreg_comm.blinders.clone()));
1343
1344 let table_blinding = {
1346 let joint_combiner = lookup_context.joint_combiner.as_ref().unwrap();
1347 let table_id_combiner = lookup_context.table_id_combiner.as_ref().unwrap();
1348 let max_fixed_lookup_table_size = {
1349 lcs.lookup_table8.len()
1357 };
1358 let base_blinding = {
1359 let fixed_table_blinding = if max_fixed_lookup_table_size == 0 {
1360 G::ScalarField::zero()
1361 } else {
1362 (1..max_fixed_lookup_table_size).fold(G::ScalarField::one(), |acc, _| {
1363 G::ScalarField::one() + *joint_combiner * acc
1364 })
1365 };
1366 fixed_table_blinding + *table_id_combiner
1367 };
1368 if lcs.runtime_selector.is_some() {
1369 let runtime_comm = lookup_context.runtime_table_comm.as_ref().unwrap();
1370
1371 let chunks = runtime_comm
1372 .blinders
1373 .into_iter()
1374 .map(|blinding| *joint_combiner * *blinding + base_blinding)
1375 .collect();
1376
1377 PolyComm::new(chunks)
1378 } else {
1379 let chunks = vec![base_blinding; num_chunks];
1380 PolyComm::new(chunks)
1381 }
1382 };
1383
1384 let joint_lookup_table = lookup_context.joint_lookup_table.as_ref().unwrap();
1385
1386 polynomials.push((coefficients_form(joint_lookup_table), table_blinding));
1387
1388 if lcs.runtime_selector.is_some() {
1390 let runtime_table_comm = lookup_context.runtime_table_comm.as_ref().unwrap();
1391 let runtime_table = lookup_context.runtime_table.as_ref().unwrap();
1392
1393 polynomials.push((
1394 coefficients_form(runtime_table),
1395 runtime_table_comm.blinders.clone(),
1396 ));
1397 }
1398
1399 if let Some(runtime_lookup_table_selector) = &lcs.runtime_selector {
1402 polynomials.push((
1403 evaluations_form(runtime_lookup_table_selector),
1404 non_hiding(1),
1405 ))
1406 }
1407 if let Some(xor_lookup_selector) = &lcs.lookup_selectors.xor {
1408 polynomials.push((evaluations_form(xor_lookup_selector), non_hiding(1)))
1409 }
1410 if let Some(lookup_gate_selector) = &lcs.lookup_selectors.lookup {
1411 polynomials.push((evaluations_form(lookup_gate_selector), non_hiding(1)))
1412 }
1413 if let Some(range_check_lookup_selector) = &lcs.lookup_selectors.range_check {
1414 polynomials.push((evaluations_form(range_check_lookup_selector), non_hiding(1)))
1415 }
1416 if let Some(foreign_field_mul_lookup_selector) = &lcs.lookup_selectors.ffmul {
1417 polynomials.push((
1418 evaluations_form(foreign_field_mul_lookup_selector),
1419 non_hiding(1),
1420 ))
1421 }
1422 }
1423
1424 internal_tracing::checkpoint!(internal_traces; create_aggregated_ipa);
1426 let proof = OpenProof::open(
1427 &*index.srs,
1428 group_map,
1429 &polynomials,
1430 &[zeta, zeta_omega],
1431 v,
1432 u,
1433 fq_sponge_before_evaluations,
1434 rng,
1435 );
1436
1437 let lookup = lookup_context
1438 .aggreg_comm
1439 .zip(lookup_context.sorted_comms)
1440 .map(|(a, s)| LookupCommitments {
1441 aggreg: a.commitment,
1442 sorted: s.iter().map(|c| c.commitment.clone()).collect(),
1443 runtime: lookup_context.runtime_table_comm.map(|x| x.commitment),
1444 });
1445
1446 let proof = Self {
1447 commitments: ProverCommitments {
1448 w_comm: array::from_fn(|i| w_comm[i].commitment.clone()),
1449 z_comm: z_comm.commitment,
1450 t_comm: t_comm.commitment,
1451 lookup,
1452 },
1453 proof,
1454 evals: chunked_evals,
1455 ft_eval1,
1456 prev_challenges,
1457 };
1458
1459 internal_tracing::checkpoint!(internal_traces; create_recursive_done);
1460
1461 Ok(proof)
1462 }
1463}
1464
1465internal_tracing::decl_traces!(internal_traces;
1466 pasta_fp_plonk_proof_create,
1467 pasta_fq_plonk_proof_create,
1468 create_recursive,
1469 pad_witness,
1470 set_up_fq_sponge,
1471 commit_to_witness_columns,
1472 use_lookup,
1473 z_permutation_aggregation_polynomial,
1474 eval_witness_polynomials_over_domains,
1475 compute_index_evals,
1476 compute_quotient_poly,
1477 lagrange_basis_eval_zeta_poly,
1478 lagrange_basis_eval_zeta_omega_poly,
1479 chunk_eval_zeta_omega_poly,
1480 compute_ft_poly,
1481 ft_eval_zeta_omega,
1482 build_polynomials,
1483 create_aggregated_ipa,
1484 create_recursive_done);
1485
1486#[cfg(feature = "ocaml_types")]
1487pub mod caml {
1488 use super::*;
1489 use crate::proof::caml::{CamlProofEvaluations, CamlRecursionChallenge};
1490 use ark_ec::AffineRepr;
1491 use poly_commitment::{
1492 commitment::caml::CamlPolyComm,
1493 ipa::{caml::CamlOpeningProof, OpeningProof},
1494 };
1495
1496 #[cfg(feature = "internal_tracing")]
1497 pub use internal_traces::caml::CamlTraces as CamlProverTraces;
1498
1499 #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1500 pub struct CamlProofWithPublic<CamlG, CamlF> {
1501 pub public_evals: Option<PointEvaluations<Vec<CamlF>>>,
1502 pub proof: CamlProverProof<CamlG, CamlF>,
1503 }
1504
1505 #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1510 pub struct CamlProverProof<CamlG, CamlF> {
1511 pub commitments: CamlProverCommitments<CamlG>,
1512 pub proof: CamlOpeningProof<CamlG, CamlF>,
1513 pub evals: CamlProofEvaluations<CamlF>,
1515 pub ft_eval1: CamlF,
1516 pub public: Vec<CamlF>,
1517 pub prev_challenges: Vec<CamlRecursionChallenge<CamlG, CamlF>>,
1519 }
1520
1521 #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1526 pub struct CamlLookupCommitments<CamlG> {
1527 pub sorted: Vec<CamlPolyComm<CamlG>>,
1528 pub aggreg: CamlPolyComm<CamlG>,
1529 pub runtime: Option<CamlPolyComm<CamlG>>,
1530 }
1531
1532 #[allow(clippy::type_complexity)]
1533 #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1534 pub struct CamlProverCommitments<CamlG> {
1535 pub w_comm: (
1537 CamlPolyComm<CamlG>,
1538 CamlPolyComm<CamlG>,
1539 CamlPolyComm<CamlG>,
1540 CamlPolyComm<CamlG>,
1541 CamlPolyComm<CamlG>,
1542 CamlPolyComm<CamlG>,
1543 CamlPolyComm<CamlG>,
1544 CamlPolyComm<CamlG>,
1545 CamlPolyComm<CamlG>,
1546 CamlPolyComm<CamlG>,
1547 CamlPolyComm<CamlG>,
1548 CamlPolyComm<CamlG>,
1549 CamlPolyComm<CamlG>,
1550 CamlPolyComm<CamlG>,
1551 CamlPolyComm<CamlG>,
1552 ),
1553 pub z_comm: CamlPolyComm<CamlG>,
1554 pub t_comm: CamlPolyComm<CamlG>,
1555 pub lookup: Option<CamlLookupCommitments<CamlG>>,
1556 }
1557
1558 impl<G, CamlG> From<LookupCommitments<G>> for CamlLookupCommitments<CamlG>
1580 where
1581 G: AffineRepr,
1582 CamlPolyComm<CamlG>: From<PolyComm<G>>,
1583 {
1584 fn from(
1585 LookupCommitments {
1586 aggreg,
1587 sorted,
1588 runtime,
1589 }: LookupCommitments<G>,
1590 ) -> Self {
1591 Self {
1592 aggreg: aggreg.into(),
1593 sorted: sorted.into_iter().map(Into::into).collect(),
1594 runtime: runtime.map(Into::into),
1595 }
1596 }
1597 }
1598
1599 impl<G, CamlG> From<CamlLookupCommitments<CamlG>> for LookupCommitments<G>
1600 where
1601 G: AffineRepr,
1602 PolyComm<G>: From<CamlPolyComm<CamlG>>,
1603 {
1604 fn from(
1605 CamlLookupCommitments {
1606 aggreg,
1607 sorted,
1608 runtime,
1609 }: CamlLookupCommitments<CamlG>,
1610 ) -> LookupCommitments<G> {
1611 LookupCommitments {
1612 aggreg: aggreg.into(),
1613 sorted: sorted.into_iter().map(Into::into).collect(),
1614 runtime: runtime.map(Into::into),
1615 }
1616 }
1617 }
1618
1619 impl<G, CamlG> From<ProverCommitments<G>> for CamlProverCommitments<CamlG>
1624 where
1625 G: AffineRepr,
1626 CamlPolyComm<CamlG>: From<PolyComm<G>>,
1627 {
1628 fn from(prover_comm: ProverCommitments<G>) -> Self {
1629 let [w_comm0, w_comm1, w_comm2, w_comm3, w_comm4, w_comm5, w_comm6, w_comm7, w_comm8, w_comm9, w_comm10, w_comm11, w_comm12, w_comm13, w_comm14] =
1630 prover_comm.w_comm;
1631 Self {
1632 w_comm: (
1633 w_comm0.into(),
1634 w_comm1.into(),
1635 w_comm2.into(),
1636 w_comm3.into(),
1637 w_comm4.into(),
1638 w_comm5.into(),
1639 w_comm6.into(),
1640 w_comm7.into(),
1641 w_comm8.into(),
1642 w_comm9.into(),
1643 w_comm10.into(),
1644 w_comm11.into(),
1645 w_comm12.into(),
1646 w_comm13.into(),
1647 w_comm14.into(),
1648 ),
1649 z_comm: prover_comm.z_comm.into(),
1650 t_comm: prover_comm.t_comm.into(),
1651 lookup: prover_comm.lookup.map(Into::into),
1652 }
1653 }
1654 }
1655
1656 impl<G, CamlG> From<CamlProverCommitments<CamlG>> for ProverCommitments<G>
1657 where
1658 G: AffineRepr,
1659 PolyComm<G>: From<CamlPolyComm<CamlG>>,
1660 {
1661 fn from(caml_prover_comm: CamlProverCommitments<CamlG>) -> ProverCommitments<G> {
1662 let (
1663 w_comm0,
1664 w_comm1,
1665 w_comm2,
1666 w_comm3,
1667 w_comm4,
1668 w_comm5,
1669 w_comm6,
1670 w_comm7,
1671 w_comm8,
1672 w_comm9,
1673 w_comm10,
1674 w_comm11,
1675 w_comm12,
1676 w_comm13,
1677 w_comm14,
1678 ) = caml_prover_comm.w_comm;
1679 ProverCommitments {
1680 w_comm: [
1681 w_comm0.into(),
1682 w_comm1.into(),
1683 w_comm2.into(),
1684 w_comm3.into(),
1685 w_comm4.into(),
1686 w_comm5.into(),
1687 w_comm6.into(),
1688 w_comm7.into(),
1689 w_comm8.into(),
1690 w_comm9.into(),
1691 w_comm10.into(),
1692 w_comm11.into(),
1693 w_comm12.into(),
1694 w_comm13.into(),
1695 w_comm14.into(),
1696 ],
1697 z_comm: caml_prover_comm.z_comm.into(),
1698 t_comm: caml_prover_comm.t_comm.into(),
1699 lookup: caml_prover_comm.lookup.map(Into::into),
1700 }
1701 }
1702 }
1703
1704 #[allow(type_alias_bounds)]
1711 type ProofTuple<const FULL_ROUNDS: usize, G: AffineRepr> = (
1712 ProverProof<G, OpeningProof<G, FULL_ROUNDS>, FULL_ROUNDS>,
1713 Vec<<G as AffineRepr>::ScalarField>,
1714 );
1715
1716 impl<const FULL_ROUNDS: usize, G, CamlG, CamlF> From<ProofTuple<FULL_ROUNDS, G>>
1717 for CamlProofWithPublic<CamlG, CamlF>
1718 where
1719 G: AffineRepr,
1720 G::BaseField: PrimeField,
1721 G: poly_commitment::commitment::EndoCurve,
1722 CamlG: From<G>,
1723 CamlF: From<G::ScalarField>,
1724 {
1725 fn from(pp: ProofTuple<FULL_ROUNDS, G>) -> Self {
1726 let (public_evals, evals) = pp.0.evals.into();
1727 CamlProofWithPublic {
1728 public_evals,
1729 proof: CamlProverProof {
1730 commitments: pp.0.commitments.into(),
1731 proof: pp.0.proof.into(),
1732 evals,
1733 ft_eval1: pp.0.ft_eval1.into(),
1734 public: pp.1.into_iter().map(Into::into).collect(),
1735 prev_challenges: pp.0.prev_challenges.into_iter().map(Into::into).collect(),
1736 },
1737 }
1738 }
1739 }
1740
1741 impl<const FULL_ROUNDS: usize, G, CamlG, CamlF> From<CamlProofWithPublic<CamlG, CamlF>>
1742 for ProofTuple<FULL_ROUNDS, G>
1743 where
1744 CamlF: Clone,
1745 G: AffineRepr + From<CamlG>,
1746 G::BaseField: PrimeField,
1747 G: poly_commitment::commitment::EndoCurve,
1748 G::ScalarField: From<CamlF>,
1749 {
1750 fn from(caml_pp: CamlProofWithPublic<CamlG, CamlF>) -> Self {
1751 let CamlProofWithPublic {
1752 public_evals,
1753 proof: caml_pp,
1754 } = caml_pp;
1755 let proof = ProverProof {
1756 commitments: caml_pp.commitments.into(),
1757 proof: caml_pp.proof.into(),
1758 evals: (public_evals, caml_pp.evals).into(),
1759 ft_eval1: caml_pp.ft_eval1.into(),
1760 prev_challenges: caml_pp
1761 .prev_challenges
1762 .into_iter()
1763 .map(Into::into)
1764 .collect(),
1765 };
1766
1767 (proof, caml_pp.public.into_iter().map(Into::into).collect())
1768 }
1769 }
1770}