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 =
464 ScalarChallenge::new(joint_combiner).to_field(endo_r);
465
466 let table_id_combiner: G::ScalarField = if lcs.table_ids8.as_ref().is_some() {
470 joint_combiner.pow([lcs.configuration.lookup_info.max_joint_size as u64])
471 } else {
472 G::ScalarField::zero()
474 };
475 lookup_context.table_id_combiner = Some(table_id_combiner);
476
477 let dummy_lookup_value = lcs
480 .configuration
481 .dummy_lookup
482 .evaluate(&joint_combiner, &table_id_combiner);
483 lookup_context.dummy_lookup_value = Some(dummy_lookup_value);
484
485 let joint_lookup_table_d8 = {
487 let mut evals = Vec::with_capacity(d1_size);
488
489 for idx in 0..(d1_size * 8) {
490 let table_id = match lcs.table_ids8.as_ref() {
491 Some(table_ids8) => table_ids8.evals[idx],
492 None =>
493 {
496 G::ScalarField::zero()
497 }
498 };
499
500 let combined_entry =
501 if !lcs.configuration.lookup_info.features.uses_runtime_tables {
502 let table_row = lcs.lookup_table8.iter().map(|e| &e.evals[idx]);
503
504 combine_table_entry(
505 &joint_combiner,
506 &table_id_combiner,
507 table_row,
508 &table_id,
509 )
510 } else {
511 let second_col = lookup_context.runtime_second_col_d8.as_ref().unwrap();
513
514 let table_row = lcs.lookup_table8.iter().enumerate().map(|(col, e)| {
515 if col == 1 {
516 &second_col.evals[idx]
517 } else {
518 &e.evals[idx]
519 }
520 });
521
522 combine_table_entry(
523 &joint_combiner,
524 &table_id_combiner,
525 table_row,
526 &table_id,
527 )
528 };
529 evals.push(combined_entry);
530 }
531
532 Evaluations::from_vec_and_domain(evals, index.cs.domain.d8)
533 };
534
535 let joint_lookup_table = joint_lookup_table_d8.interpolate_by_ref();
537
538 let sorted: Vec<_> = lookup::constraints::sorted(
543 dummy_lookup_value,
544 &joint_lookup_table_d8,
545 index.cs.domain.d1,
546 &index.cs.gates,
547 &witness,
548 joint_combiner,
549 table_id_combiner,
550 &lcs.configuration.lookup_info,
551 index.cs.zk_rows as usize,
552 )?;
553
554 let sorted: Vec<_> = sorted
557 .into_iter()
558 .map(|chunk| {
559 lookup::constraints::zk_patch(
560 chunk,
561 index.cs.domain.d1,
562 index.cs.zk_rows as usize,
563 rng,
564 )
565 })
566 .collect();
567
568 let sorted_comms: Vec<_> = sorted
570 .iter()
571 .map(|v| index.srs.commit_evaluations(index.cs.domain.d1, v, rng))
572 .collect();
573
574 sorted_comms
576 .iter()
577 .for_each(|c| absorb_commitment(&mut fq_sponge, &c.commitment));
578
579 let sorted_coeffs: Vec<_> = sorted.iter().map(|e| e.clone().interpolate()).collect();
582 let sorted8: Vec<_> = sorted_coeffs
583 .iter()
584 .map(|v| v.evaluate_over_domain_by_ref(index.cs.domain.d8))
585 .collect();
586
587 lookup_context.joint_combiner = Some(joint_combiner);
588 lookup_context.sorted = Some(sorted);
589 lookup_context.sorted_coeffs = Some(sorted_coeffs);
590 lookup_context.sorted_comms = Some(sorted_comms);
591 lookup_context.sorted8 = Some(sorted8);
592 lookup_context.joint_lookup_table_d8 = Some(joint_lookup_table_d8);
593 lookup_context.joint_lookup_table = Some(joint_lookup_table);
594 }
595
596 let beta = fq_sponge.challenge();
598
599 let gamma = fq_sponge.challenge();
601
602 if let Some(lcs) = lookup_constraint_system {
604 let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap();
606
607 let aggreg = lookup::constraints::aggregation::<_, G::ScalarField>(
608 lookup_context.dummy_lookup_value.unwrap(),
609 joint_lookup_table_d8,
610 index.cs.domain.d1,
611 &index.cs.gates,
612 &witness,
613 &lookup_context.joint_combiner.unwrap(),
614 &lookup_context.table_id_combiner.unwrap(),
615 beta,
616 gamma,
617 lookup_context.sorted.as_ref().unwrap(),
618 rng,
619 &lcs.configuration.lookup_info,
620 index.cs.zk_rows as usize,
621 )?;
622
623 let aggreg_comm = index
625 .srs
626 .commit_evaluations(index.cs.domain.d1, &aggreg, rng);
627
628 absorb_commitment(&mut fq_sponge, &aggreg_comm.commitment);
630
631 let aggreg_coeffs = aggreg.interpolate();
633 let aggreg8 = aggreg_coeffs.evaluate_over_domain_by_ref(index.cs.domain.d8);
636
637 lookup_context.aggreg_comm = Some(aggreg_comm);
638 lookup_context.aggreg_coeffs = Some(aggreg_coeffs);
639 lookup_context.aggreg8 = Some(aggreg8);
640 }
641
642 let column_evaluations = index.column_evaluations.get();
643
644 internal_tracing::checkpoint!(internal_traces; z_permutation_aggregation_polynomial);
646 let z_poly = index.perm_aggreg(&witness, &beta, &gamma, rng)?;
647
648 let z_comm = index.srs.commit(&z_poly, num_chunks, rng);
650
651 absorb_commitment(&mut fq_sponge, &z_comm.commitment);
653
654 let alpha_chal = ScalarChallenge::new(fq_sponge.challenge());
656
657 let alpha: G::ScalarField = alpha_chal.to_field(endo_r);
659
660 let mut all_alphas = index.powers_of_alpha.clone();
662 all_alphas.instantiate(alpha);
663
664 let lookup_env = if let Some(lcs) = lookup_constraint_system {
673 let joint_lookup_table_d8 = lookup_context.joint_lookup_table_d8.as_ref().unwrap();
674
675 Some(LookupEnvironment {
676 aggreg: lookup_context.aggreg8.as_ref().unwrap(),
677 sorted: lookup_context.sorted8.as_ref().unwrap(),
678 selectors: &lcs.lookup_selectors,
679 table: joint_lookup_table_d8,
680 runtime_selector: lcs.runtime_selector.as_ref(),
681 runtime_table: lookup_context.runtime_table_d8.as_ref(),
682 })
683 } else {
684 None
685 };
686
687 internal_tracing::checkpoint!(internal_traces; eval_witness_polynomials_over_domains);
688 let lagrange = index.cs.evaluate(&witness_poly, &z_poly);
689 internal_tracing::checkpoint!(internal_traces; compute_index_evals);
690 let env = {
691 let mut index_evals = HashMap::new();
692 use GateType::*;
693 index_evals.insert(Generic, &column_evaluations.generic_selector4);
694 index_evals.insert(Poseidon, &column_evaluations.poseidon_selector8);
695 index_evals.insert(CompleteAdd, &column_evaluations.complete_add_selector4);
696 index_evals.insert(VarBaseMul, &column_evaluations.mul_selector8);
697 index_evals.insert(EndoMul, &column_evaluations.emul_selector8);
698 index_evals.insert(EndoMulScalar, &column_evaluations.endomul_scalar_selector8);
699
700 if let Some(selector) = &column_evaluations.range_check0_selector8 {
701 index_evals.insert(GateType::RangeCheck0, selector);
702 }
703
704 if let Some(selector) = &column_evaluations.range_check1_selector8 {
705 index_evals.insert(GateType::RangeCheck1, selector);
706 }
707
708 if let Some(selector) = &column_evaluations.foreign_field_add_selector8 {
709 index_evals.insert(GateType::ForeignFieldAdd, selector);
710 }
711
712 if let Some(selector) = &column_evaluations.foreign_field_mul_selector8 {
713 index_evals.extend(
714 foreign_field_mul::gadget::circuit_gates()
715 .iter()
716 .map(|gate_type| (*gate_type, selector)),
717 );
718 }
719
720 if let Some(selector) = &column_evaluations.xor_selector8 {
721 index_evals.insert(GateType::Xor16, selector);
722 }
723
724 if let Some(selector) = &column_evaluations.rot_selector8 {
725 index_evals.insert(GateType::Rot64, selector);
726 }
727
728 let mds = &G::sponge_params().mds;
729 Environment {
730 constants: Constants {
731 endo_coefficient: index.cs.endo,
732 mds,
733 zk_rows: index.cs.zk_rows,
734 },
735 challenges: BerkeleyChallenges {
736 alpha,
737 beta,
738 gamma,
739 joint_combiner: lookup_context
740 .joint_combiner
741 .unwrap_or(G::ScalarField::zero()),
742 },
743 witness: &lagrange.d8.this.w,
744 coefficient: &column_evaluations.coefficients8,
745 vanishes_on_zero_knowledge_and_previous_rows: &index
746 .cs
747 .precomputations()
748 .vanishes_on_zero_knowledge_and_previous_rows,
749 z: &lagrange.d8.this.z,
750 l0_1: l0_1(index.cs.domain.d1),
751 domain: index.cs.domain,
752 index: index_evals,
753 lookup: lookup_env,
754 }
755 };
756
757 let mut cache = expr::Cache::default();
758
759 internal_tracing::checkpoint!(internal_traces; compute_quotient_poly);
760
761 let quotient_poly = {
762 let mut t4 = {
764 let generic_constraint =
765 generic::Generic::combined_constraints(&all_alphas, &mut cache);
766 let generic4 = generic_constraint.evaluations(&env);
767
768 if cfg!(debug_assertions) {
769 let p4 = public_poly.evaluate_over_domain_by_ref(index.cs.domain.d4);
770 let gen_minus_pub = &generic4 + &p4;
771
772 check_constraint!(index, gen_minus_pub);
773 }
774
775 generic4
776 };
777
778 let (mut t8, bnd) = {
780 let alphas =
781 all_alphas.get_alphas(ArgumentType::Permutation, permutation::CONSTRAINTS);
782 let (perm, bnd) = index.perm_quot(&lagrange, beta, gamma, &z_poly, alphas)?;
783
784 check_constraint!(index, perm);
785
786 (perm, bnd)
787 };
788
789 {
790 use crate::circuits::argument::DynArgument;
791
792 let range_check0_enabled = column_evaluations.range_check0_selector8.is_some();
793 let range_check1_enabled = column_evaluations.range_check1_selector8.is_some();
794 let foreign_field_addition_enabled =
795 column_evaluations.foreign_field_add_selector8.is_some();
796 let foreign_field_multiplication_enabled =
797 column_evaluations.foreign_field_mul_selector8.is_some();
798 let xor_enabled = column_evaluations.xor_selector8.is_some();
799 let rot_enabled = column_evaluations.rot_selector8.is_some();
800
801 for gate in [
802 (
803 (&CompleteAdd::default() as &dyn DynArgument<G::ScalarField>),
804 true,
805 ),
806 (&VarbaseMul::default(), true),
807 (&EndosclMul::default(), true),
808 (&EndomulScalar::default(), true),
809 (&Poseidon::default(), true),
810 (&RangeCheck0::default(), range_check0_enabled),
812 (&RangeCheck1::default(), range_check1_enabled),
813 (&ForeignFieldAdd::default(), foreign_field_addition_enabled),
815 (
817 &ForeignFieldMul::default(),
818 foreign_field_multiplication_enabled,
819 ),
820 (&Xor16::default(), xor_enabled),
822 (&Rot64::default(), rot_enabled),
824 ]
825 .into_iter()
826 .filter_map(|(gate, is_enabled)| if is_enabled { Some(gate) } else { None })
827 {
828 let constraint = gate.combined_constraints(&all_alphas, &mut cache);
829 let eval = constraint.evaluations(&env);
830 if eval.domain().size == t4.domain().size {
831 t4 += &eval;
832 } else if eval.domain().size == t8.domain().size {
833 t8 += &eval;
834 } else {
835 panic!("Bad evaluation")
836 }
837 check_constraint!(index, format!("{:?}", gate.argument_type()), eval);
838 }
839 };
840
841 {
843 if let Some(lcs) = lookup_constraint_system {
844 let constraints = lookup::constraints::constraints(&lcs.configuration, false);
845 let constraints_len = u32::try_from(constraints.len())
846 .expect("not expecting a large amount of constraints");
847 let lookup_alphas =
848 all_alphas.get_alphas(ArgumentType::Lookup, constraints_len);
849
850 for (ii, (constraint, alpha_pow)) in
853 constraints.into_iter().zip_eq(lookup_alphas).enumerate()
854 {
855 let mut eval = constraint.evaluations(&env);
856 eval.evals.par_iter_mut().for_each(|x| *x *= alpha_pow);
857
858 if eval.domain().size == t4.domain().size {
859 t4 += &eval;
860 } else if eval.domain().size == t8.domain().size {
861 t8 += &eval;
862 } else if eval.evals.iter().all(|x| x.is_zero()) {
863 } else {
865 panic!("Bad evaluation")
866 }
867
868 check_constraint!(index, format!("lookup constraint #{ii}"), eval);
869 }
870 }
871 }
872
873 let mut f = t4.interpolate() + t8.interpolate();
875 f += &public_poly;
876
877 let (mut quotient, res) = f.divide_by_vanishing_poly(index.cs.domain.d1);
879 if !res.is_zero() {
880 return Err(ProverError::Prover(
881 "rest of division by vanishing polynomial",
882 ));
883 }
884
885 quotient += &bnd; quotient
887 };
888
889 let t_comm = { index.srs.commit("ient_poly, 7 * num_chunks, rng) };
891
892 absorb_commitment(&mut fq_sponge, &t_comm.commitment);
894
895 let zeta_chal = ScalarChallenge::new(fq_sponge.challenge());
897
898 let zeta = zeta_chal.to_field(endo_r);
900
901 let omega = index.cs.domain.d1.group_gen;
902 let zeta_omega = zeta * omega;
903
904 if lookup_constraint_system.is_some() {
906 let aggreg = lookup_context
908 .aggreg_coeffs
909 .as_ref()
910 .unwrap()
911 .to_chunked_polynomial(num_chunks, index.max_poly_size);
912
913 let sorted = lookup_context
915 .sorted_coeffs
916 .as_ref()
917 .unwrap()
918 .iter()
919 .map(|c| c.to_chunked_polynomial(num_chunks, index.max_poly_size))
920 .collect::<Vec<_>>();
921
922 let joint_table = lookup_context.joint_lookup_table.as_ref().unwrap();
924 let joint_table = joint_table.to_chunked_polynomial(num_chunks, index.max_poly_size);
925
926 lookup_context.lookup_aggregation_eval = Some(PointEvaluations {
927 zeta: aggreg.evaluate_chunks(zeta),
928 zeta_omega: aggreg.evaluate_chunks(zeta_omega),
929 });
930 lookup_context.lookup_table_eval = Some(PointEvaluations {
931 zeta: joint_table.evaluate_chunks(zeta),
932 zeta_omega: joint_table.evaluate_chunks(zeta_omega),
933 });
934 lookup_context.lookup_sorted_eval = array::from_fn(|i| {
935 if i < sorted.len() {
936 let sorted = &sorted[i];
937 Some(PointEvaluations {
938 zeta: sorted.evaluate_chunks(zeta),
939 zeta_omega: sorted.evaluate_chunks(zeta_omega),
940 })
941 } else {
942 None
943 }
944 });
945 lookup_context.runtime_lookup_table_eval =
946 lookup_context.runtime_table.as_ref().map(|runtime_table| {
947 let runtime_table =
948 runtime_table.to_chunked_polynomial(num_chunks, index.max_poly_size);
949 PointEvaluations {
950 zeta: runtime_table.evaluate_chunks(zeta),
951 zeta_omega: runtime_table.evaluate_chunks(zeta_omega),
952 }
953 });
954 }
955
956 internal_tracing::checkpoint!(internal_traces; lagrange_basis_eval_zeta_poly);
976 let zeta_evals =
977 LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta);
978 internal_tracing::checkpoint!(internal_traces; lagrange_basis_eval_zeta_omega_poly);
979 let zeta_omega_evals =
980 LagrangeBasisEvaluations::new(index.max_poly_size, index.cs.domain.d1, zeta_omega);
981
982 let chunked_evals_for_selector =
983 |p: &Evaluations<G::ScalarField, D<G::ScalarField>>| PointEvaluations {
984 zeta: zeta_evals.evaluate_boolean(p),
985 zeta_omega: zeta_omega_evals.evaluate_boolean(p),
986 };
987
988 let chunked_evals_for_evaluations =
989 |p: &Evaluations<G::ScalarField, D<G::ScalarField>>| PointEvaluations {
990 zeta: zeta_evals.evaluate(p),
991 zeta_omega: zeta_omega_evals.evaluate(p),
992 };
993
994 internal_tracing::checkpoint!(internal_traces; chunk_eval_zeta_omega_poly);
995 let chunked_evals = ProofEvaluations::<PointEvaluations<Vec<G::ScalarField>>> {
996 public: {
997 let chunked = public_poly.to_chunked_polynomial(num_chunks, index.max_poly_size);
998 Some(PointEvaluations {
999 zeta: chunked.evaluate_chunks(zeta),
1000 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1001 })
1002 },
1003 s: array::from_fn(|i| {
1004 chunked_evals_for_evaluations(&column_evaluations.permutation_coefficients8[i])
1005 }),
1006 coefficients: array::from_fn(|i| {
1007 chunked_evals_for_evaluations(&column_evaluations.coefficients8[i])
1008 }),
1009 w: array::from_fn(|i| {
1010 let chunked =
1011 witness_poly[i].to_chunked_polynomial(num_chunks, index.max_poly_size);
1012 PointEvaluations {
1013 zeta: chunked.evaluate_chunks(zeta),
1014 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1015 }
1016 }),
1017
1018 z: {
1019 let chunked = z_poly.to_chunked_polynomial(num_chunks, index.max_poly_size);
1020 PointEvaluations {
1021 zeta: chunked.evaluate_chunks(zeta),
1022 zeta_omega: chunked.evaluate_chunks(zeta_omega),
1023 }
1024 },
1025
1026 lookup_aggregation: lookup_context.lookup_aggregation_eval.take(),
1027 lookup_table: lookup_context.lookup_table_eval.take(),
1028 lookup_sorted: array::from_fn(|i| lookup_context.lookup_sorted_eval[i].take()),
1029 runtime_lookup_table: lookup_context.runtime_lookup_table_eval.take(),
1030 generic_selector: chunked_evals_for_selector(&column_evaluations.generic_selector4),
1031 poseidon_selector: chunked_evals_for_selector(&column_evaluations.poseidon_selector8),
1032 complete_add_selector: chunked_evals_for_selector(
1033 &column_evaluations.complete_add_selector4,
1034 ),
1035 mul_selector: chunked_evals_for_selector(&column_evaluations.mul_selector8),
1036 emul_selector: chunked_evals_for_selector(&column_evaluations.emul_selector8),
1037 endomul_scalar_selector: chunked_evals_for_selector(
1038 &column_evaluations.endomul_scalar_selector8,
1039 ),
1040
1041 range_check0_selector: column_evaluations
1042 .range_check0_selector8
1043 .as_ref()
1044 .map(chunked_evals_for_selector),
1045 range_check1_selector: column_evaluations
1046 .range_check1_selector8
1047 .as_ref()
1048 .map(chunked_evals_for_selector),
1049 foreign_field_add_selector: column_evaluations
1050 .foreign_field_add_selector8
1051 .as_ref()
1052 .map(chunked_evals_for_selector),
1053 foreign_field_mul_selector: column_evaluations
1054 .foreign_field_mul_selector8
1055 .as_ref()
1056 .map(chunked_evals_for_selector),
1057 xor_selector: column_evaluations
1058 .xor_selector8
1059 .as_ref()
1060 .map(chunked_evals_for_selector),
1061 rot_selector: column_evaluations
1062 .rot_selector8
1063 .as_ref()
1064 .map(chunked_evals_for_selector),
1065
1066 runtime_lookup_table_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1067 lcs.runtime_selector
1068 .as_ref()
1069 .map(chunked_evals_for_selector)
1070 }),
1071 xor_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1072 lcs.lookup_selectors
1073 .xor
1074 .as_ref()
1075 .map(chunked_evals_for_selector)
1076 }),
1077 lookup_gate_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1078 lcs.lookup_selectors
1079 .lookup
1080 .as_ref()
1081 .map(chunked_evals_for_selector)
1082 }),
1083 range_check_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1084 lcs.lookup_selectors
1085 .range_check
1086 .as_ref()
1087 .map(chunked_evals_for_selector)
1088 }),
1089 foreign_field_mul_lookup_selector: lookup_constraint_system.as_ref().and_then(|lcs| {
1090 lcs.lookup_selectors
1091 .ffmul
1092 .as_ref()
1093 .map(chunked_evals_for_selector)
1094 }),
1095 };
1096
1097 let zeta_to_srs_len = zeta.pow([index.max_poly_size as u64]);
1098 let zeta_omega_to_srs_len = zeta_omega.pow([index.max_poly_size as u64]);
1099 let zeta_to_domain_size = zeta.pow([d1_size as u64]);
1100
1101 let evals: ProofEvaluations<PointEvaluations<G::ScalarField>> = {
1104 let powers_of_eval_points_for_chunks = PointEvaluations {
1105 zeta: zeta_to_srs_len,
1106 zeta_omega: zeta_omega_to_srs_len,
1107 };
1108 chunked_evals.combine(&powers_of_eval_points_for_chunks)
1109 };
1110
1111 internal_tracing::checkpoint!(internal_traces; compute_ft_poly);
1114 let ft: DensePolynomial<G::ScalarField> = {
1115 let f_chunked = {
1116 let alphas =
1122 all_alphas.get_alphas(ArgumentType::Permutation, permutation::CONSTRAINTS);
1123 let f = index.perm_lnrz(&evals, zeta, beta, gamma, alphas);
1124
1125 let f = {
1127 let (_lin_constant, mut lin) =
1128 index.linearization.to_polynomial(&env, zeta, &evals);
1129 lin += &f;
1130 lin.interpolate()
1131 };
1132
1133 drop(env);
1134
1135 f.to_chunked_polynomial(num_chunks, index.max_poly_size)
1137 .linearize(zeta_to_srs_len)
1138 };
1139
1140 let t_chunked = quotient_poly
1141 .to_chunked_polynomial(7 * num_chunks, index.max_poly_size)
1142 .linearize(zeta_to_srs_len);
1143
1144 &f_chunked - &t_chunked.scale(zeta_to_domain_size - G::ScalarField::one())
1145 };
1146
1147 let blinding_ft = {
1150 let blinding_t = t_comm.blinders.chunk_blinding(zeta_to_srs_len);
1151 let blinding_f = G::ScalarField::zero();
1152
1153 PolyComm {
1154 chunks: vec![
1156 blinding_f - (zeta_to_domain_size - G::ScalarField::one()) * blinding_t,
1157 ],
1158 }
1159 };
1160
1161 internal_tracing::checkpoint!(internal_traces; ft_eval_zeta_omega);
1163 let ft_eval1 = ft.evaluate(&zeta_omega);
1164
1165 let fq_sponge_before_evaluations = fq_sponge.clone();
1167 let mut fr_sponge = EFrSponge::from(G::sponge_params());
1168
1169 fr_sponge.absorb(&fq_sponge.digest());
1171
1172 let prev_challenge_digest = {
1174 let mut fr_sponge = EFrSponge::from(G::sponge_params());
1177 for RecursionChallenge { chals, .. } in &prev_challenges {
1178 fr_sponge.absorb_multiple(chals);
1179 }
1180 fr_sponge.digest()
1181 };
1182 fr_sponge.absorb(&prev_challenge_digest);
1183
1184 internal_tracing::checkpoint!(internal_traces; build_polynomials);
1186 let polys = prev_challenges
1187 .iter()
1188 .map(|RecursionChallenge { chals, comm }| {
1189 (
1190 DensePolynomial::from_coefficients_vec(b_poly_coefficients(chals)),
1191 comm.len(),
1192 )
1193 })
1194 .collect::<Vec<_>>();
1195
1196 fr_sponge.absorb(&ft_eval1);
1198
1199 fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta);
1207 fr_sponge.absorb_multiple(&chunked_evals.public.as_ref().unwrap().zeta_omega);
1208 fr_sponge.absorb_evaluations(&chunked_evals);
1209
1210 let v_chal = fr_sponge.challenge();
1212
1213 let v = v_chal.to_field(endo_r);
1215
1216 let u_chal = fr_sponge.challenge();
1218
1219 let u = u_chal.to_field(endo_r);
1221
1222 let non_hiding = |n_chunks: usize| PolyComm {
1226 chunks: vec![G::ScalarField::zero(); n_chunks],
1227 };
1228
1229 let fixed_hiding = |n_chunks: usize| PolyComm {
1230 chunks: vec![G::ScalarField::one(); n_chunks],
1231 };
1232
1233 let coefficients_form = DensePolynomialOrEvaluations::DensePolynomial;
1234 let evaluations_form = |e| DensePolynomialOrEvaluations::Evaluations(e, index.cs.domain.d1);
1235
1236 let mut polynomials = polys
1237 .iter()
1238 .map(|(p, n_chunks)| (coefficients_form(p), non_hiding(*n_chunks)))
1239 .collect::<Vec<_>>();
1240
1241 polynomials.push((coefficients_form(&public_poly), fixed_hiding(num_chunks)));
1250 polynomials.push((coefficients_form(&ft), blinding_ft));
1251 polynomials.push((coefficients_form(&z_poly), z_comm.blinders));
1252 polynomials.push((
1253 evaluations_form(&column_evaluations.generic_selector4),
1254 fixed_hiding(num_chunks),
1255 ));
1256 polynomials.push((
1257 evaluations_form(&column_evaluations.poseidon_selector8),
1258 fixed_hiding(num_chunks),
1259 ));
1260 polynomials.push((
1261 evaluations_form(&column_evaluations.complete_add_selector4),
1262 fixed_hiding(num_chunks),
1263 ));
1264 polynomials.push((
1265 evaluations_form(&column_evaluations.mul_selector8),
1266 fixed_hiding(num_chunks),
1267 ));
1268 polynomials.push((
1269 evaluations_form(&column_evaluations.emul_selector8),
1270 fixed_hiding(num_chunks),
1271 ));
1272 polynomials.push((
1273 evaluations_form(&column_evaluations.endomul_scalar_selector8),
1274 fixed_hiding(num_chunks),
1275 ));
1276 polynomials.extend(
1277 witness_poly
1278 .iter()
1279 .zip(w_comm.iter())
1280 .map(|(w, c)| (coefficients_form(w), c.blinders.clone()))
1281 .collect::<Vec<_>>(),
1282 );
1283 polynomials.extend(
1284 column_evaluations
1285 .coefficients8
1286 .iter()
1287 .map(|coefficientm| (evaluations_form(coefficientm), non_hiding(num_chunks)))
1288 .collect::<Vec<_>>(),
1289 );
1290 polynomials.extend(
1291 column_evaluations.permutation_coefficients8[0..PERMUTS - 1]
1292 .iter()
1293 .map(|w| (evaluations_form(w), non_hiding(num_chunks)))
1294 .collect::<Vec<_>>(),
1295 );
1296
1297 if let Some(range_check0_selector8) = &column_evaluations.range_check0_selector8 {
1299 polynomials.push((
1300 evaluations_form(range_check0_selector8),
1301 non_hiding(num_chunks),
1302 ));
1303 }
1304 if let Some(range_check1_selector8) = &column_evaluations.range_check1_selector8 {
1305 polynomials.push((
1306 evaluations_form(range_check1_selector8),
1307 non_hiding(num_chunks),
1308 ));
1309 }
1310 if let Some(foreign_field_add_selector8) = &column_evaluations.foreign_field_add_selector8 {
1311 polynomials.push((
1312 evaluations_form(foreign_field_add_selector8),
1313 non_hiding(num_chunks),
1314 ));
1315 }
1316 if let Some(foreign_field_mul_selector8) = &column_evaluations.foreign_field_mul_selector8 {
1317 polynomials.push((
1318 evaluations_form(foreign_field_mul_selector8),
1319 non_hiding(num_chunks),
1320 ));
1321 }
1322 if let Some(xor_selector8) = &column_evaluations.xor_selector8 {
1323 polynomials.push((evaluations_form(xor_selector8), non_hiding(num_chunks)));
1324 }
1325 if let Some(rot_selector8) = &column_evaluations.rot_selector8 {
1326 polynomials.push((evaluations_form(rot_selector8), non_hiding(num_chunks)));
1327 }
1328
1329 if let Some(lcs) = lookup_constraint_system {
1332 let sorted_poly = lookup_context.sorted_coeffs.as_ref().unwrap();
1334 let sorted_comms = lookup_context.sorted_comms.as_ref().unwrap();
1335
1336 for (poly, comm) in sorted_poly.iter().zip(sorted_comms) {
1337 polynomials.push((coefficients_form(poly), comm.blinders.clone()));
1338 }
1339
1340 let aggreg_poly = lookup_context.aggreg_coeffs.as_ref().unwrap();
1342 let aggreg_comm = lookup_context.aggreg_comm.as_ref().unwrap();
1343 polynomials.push((coefficients_form(aggreg_poly), aggreg_comm.blinders.clone()));
1344
1345 let table_blinding = {
1347 let joint_combiner = lookup_context.joint_combiner.as_ref().unwrap();
1348 let table_id_combiner = lookup_context.table_id_combiner.as_ref().unwrap();
1349 let max_fixed_lookup_table_size = {
1350 lcs.lookup_table8.len()
1358 };
1359 let base_blinding = {
1360 let fixed_table_blinding = if max_fixed_lookup_table_size == 0 {
1361 G::ScalarField::zero()
1362 } else {
1363 (1..max_fixed_lookup_table_size).fold(G::ScalarField::one(), |acc, _| {
1364 G::ScalarField::one() + *joint_combiner * acc
1365 })
1366 };
1367 fixed_table_blinding + *table_id_combiner
1368 };
1369 if lcs.runtime_selector.is_some() {
1370 let runtime_comm = lookup_context.runtime_table_comm.as_ref().unwrap();
1371
1372 let chunks = runtime_comm
1373 .blinders
1374 .into_iter()
1375 .map(|blinding| *joint_combiner * *blinding + base_blinding)
1376 .collect();
1377
1378 PolyComm::new(chunks)
1379 } else {
1380 let chunks = vec![base_blinding; num_chunks];
1381 PolyComm::new(chunks)
1382 }
1383 };
1384
1385 let joint_lookup_table = lookup_context.joint_lookup_table.as_ref().unwrap();
1386
1387 polynomials.push((coefficients_form(joint_lookup_table), table_blinding));
1388
1389 if lcs.runtime_selector.is_some() {
1391 let runtime_table_comm = lookup_context.runtime_table_comm.as_ref().unwrap();
1392 let runtime_table = lookup_context.runtime_table.as_ref().unwrap();
1393
1394 polynomials.push((
1395 coefficients_form(runtime_table),
1396 runtime_table_comm.blinders.clone(),
1397 ));
1398 }
1399
1400 if let Some(runtime_lookup_table_selector) = &lcs.runtime_selector {
1403 polynomials.push((
1404 evaluations_form(runtime_lookup_table_selector),
1405 non_hiding(1),
1406 ))
1407 }
1408 if let Some(xor_lookup_selector) = &lcs.lookup_selectors.xor {
1409 polynomials.push((evaluations_form(xor_lookup_selector), non_hiding(1)))
1410 }
1411 if let Some(lookup_gate_selector) = &lcs.lookup_selectors.lookup {
1412 polynomials.push((evaluations_form(lookup_gate_selector), non_hiding(1)))
1413 }
1414 if let Some(range_check_lookup_selector) = &lcs.lookup_selectors.range_check {
1415 polynomials.push((evaluations_form(range_check_lookup_selector), non_hiding(1)))
1416 }
1417 if let Some(foreign_field_mul_lookup_selector) = &lcs.lookup_selectors.ffmul {
1418 polynomials.push((
1419 evaluations_form(foreign_field_mul_lookup_selector),
1420 non_hiding(1),
1421 ))
1422 }
1423 }
1424
1425 internal_tracing::checkpoint!(internal_traces; create_aggregated_ipa);
1427 let proof = OpenProof::open(
1428 &*index.srs,
1429 group_map,
1430 &polynomials,
1431 &[zeta, zeta_omega],
1432 v,
1433 u,
1434 fq_sponge_before_evaluations,
1435 rng,
1436 );
1437
1438 let lookup = lookup_context
1439 .aggreg_comm
1440 .zip(lookup_context.sorted_comms)
1441 .map(|(a, s)| LookupCommitments {
1442 aggreg: a.commitment,
1443 sorted: s.iter().map(|c| c.commitment.clone()).collect(),
1444 runtime: lookup_context.runtime_table_comm.map(|x| x.commitment),
1445 });
1446
1447 let proof = Self {
1448 commitments: ProverCommitments {
1449 w_comm: array::from_fn(|i| w_comm[i].commitment.clone()),
1450 z_comm: z_comm.commitment,
1451 t_comm: t_comm.commitment,
1452 lookup,
1453 },
1454 proof,
1455 evals: chunked_evals,
1456 ft_eval1,
1457 prev_challenges,
1458 };
1459
1460 internal_tracing::checkpoint!(internal_traces; create_recursive_done);
1461
1462 Ok(proof)
1463 }
1464}
1465
1466internal_tracing::decl_traces!(internal_traces;
1467 pasta_fp_plonk_proof_create,
1468 pasta_fq_plonk_proof_create,
1469 create_recursive,
1470 pad_witness,
1471 set_up_fq_sponge,
1472 commit_to_witness_columns,
1473 use_lookup,
1474 z_permutation_aggregation_polynomial,
1475 eval_witness_polynomials_over_domains,
1476 compute_index_evals,
1477 compute_quotient_poly,
1478 lagrange_basis_eval_zeta_poly,
1479 lagrange_basis_eval_zeta_omega_poly,
1480 chunk_eval_zeta_omega_poly,
1481 compute_ft_poly,
1482 ft_eval_zeta_omega,
1483 build_polynomials,
1484 create_aggregated_ipa,
1485 create_recursive_done);
1486
1487#[cfg(feature = "ocaml_types")]
1488pub mod caml {
1489 use super::*;
1490 use crate::proof::caml::{CamlProofEvaluations, CamlRecursionChallenge};
1491 use ark_ec::AffineRepr;
1492 use poly_commitment::{
1493 commitment::caml::CamlPolyComm,
1494 ipa::{caml::CamlOpeningProof, OpeningProof},
1495 };
1496
1497 #[cfg(feature = "internal_tracing")]
1498 pub use internal_traces::caml::CamlTraces as CamlProverTraces;
1499
1500 #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1501 pub struct CamlProofWithPublic<CamlG, CamlF> {
1502 pub public_evals: Option<PointEvaluations<Vec<CamlF>>>,
1503 pub proof: CamlProverProof<CamlG, CamlF>,
1504 }
1505
1506 #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1511 pub struct CamlProverProof<CamlG, CamlF> {
1512 pub commitments: CamlProverCommitments<CamlG>,
1513 pub proof: CamlOpeningProof<CamlG, CamlF>,
1514 pub evals: CamlProofEvaluations<CamlF>,
1516 pub ft_eval1: CamlF,
1517 pub public: Vec<CamlF>,
1518 pub prev_challenges: Vec<CamlRecursionChallenge<CamlG, CamlF>>,
1520 }
1521
1522 #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1527 pub struct CamlLookupCommitments<CamlG> {
1528 pub sorted: Vec<CamlPolyComm<CamlG>>,
1529 pub aggreg: CamlPolyComm<CamlG>,
1530 pub runtime: Option<CamlPolyComm<CamlG>>,
1531 }
1532
1533 #[allow(clippy::type_complexity)]
1534 #[derive(Clone, ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1535 pub struct CamlProverCommitments<CamlG> {
1536 pub w_comm: (
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 CamlPolyComm<CamlG>,
1553 ),
1554 pub z_comm: CamlPolyComm<CamlG>,
1555 pub t_comm: CamlPolyComm<CamlG>,
1556 pub lookup: Option<CamlLookupCommitments<CamlG>>,
1557 }
1558
1559 impl<G, CamlG> From<LookupCommitments<G>> for CamlLookupCommitments<CamlG>
1581 where
1582 G: AffineRepr,
1583 CamlPolyComm<CamlG>: From<PolyComm<G>>,
1584 {
1585 fn from(
1586 LookupCommitments {
1587 aggreg,
1588 sorted,
1589 runtime,
1590 }: LookupCommitments<G>,
1591 ) -> Self {
1592 Self {
1593 aggreg: aggreg.into(),
1594 sorted: sorted.into_iter().map(Into::into).collect(),
1595 runtime: runtime.map(Into::into),
1596 }
1597 }
1598 }
1599
1600 impl<G, CamlG> From<CamlLookupCommitments<CamlG>> for LookupCommitments<G>
1601 where
1602 G: AffineRepr,
1603 PolyComm<G>: From<CamlPolyComm<CamlG>>,
1604 {
1605 fn from(
1606 CamlLookupCommitments {
1607 aggreg,
1608 sorted,
1609 runtime,
1610 }: CamlLookupCommitments<CamlG>,
1611 ) -> LookupCommitments<G> {
1612 LookupCommitments {
1613 aggreg: aggreg.into(),
1614 sorted: sorted.into_iter().map(Into::into).collect(),
1615 runtime: runtime.map(Into::into),
1616 }
1617 }
1618 }
1619
1620 impl<G, CamlG> From<ProverCommitments<G>> for CamlProverCommitments<CamlG>
1625 where
1626 G: AffineRepr,
1627 CamlPolyComm<CamlG>: From<PolyComm<G>>,
1628 {
1629 fn from(prover_comm: ProverCommitments<G>) -> Self {
1630 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] =
1631 prover_comm.w_comm;
1632 Self {
1633 w_comm: (
1634 w_comm0.into(),
1635 w_comm1.into(),
1636 w_comm2.into(),
1637 w_comm3.into(),
1638 w_comm4.into(),
1639 w_comm5.into(),
1640 w_comm6.into(),
1641 w_comm7.into(),
1642 w_comm8.into(),
1643 w_comm9.into(),
1644 w_comm10.into(),
1645 w_comm11.into(),
1646 w_comm12.into(),
1647 w_comm13.into(),
1648 w_comm14.into(),
1649 ),
1650 z_comm: prover_comm.z_comm.into(),
1651 t_comm: prover_comm.t_comm.into(),
1652 lookup: prover_comm.lookup.map(Into::into),
1653 }
1654 }
1655 }
1656
1657 impl<G, CamlG> From<CamlProverCommitments<CamlG>> for ProverCommitments<G>
1658 where
1659 G: AffineRepr,
1660 PolyComm<G>: From<CamlPolyComm<CamlG>>,
1661 {
1662 fn from(caml_prover_comm: CamlProverCommitments<CamlG>) -> ProverCommitments<G> {
1663 let (
1664 w_comm0,
1665 w_comm1,
1666 w_comm2,
1667 w_comm3,
1668 w_comm4,
1669 w_comm5,
1670 w_comm6,
1671 w_comm7,
1672 w_comm8,
1673 w_comm9,
1674 w_comm10,
1675 w_comm11,
1676 w_comm12,
1677 w_comm13,
1678 w_comm14,
1679 ) = caml_prover_comm.w_comm;
1680 ProverCommitments {
1681 w_comm: [
1682 w_comm0.into(),
1683 w_comm1.into(),
1684 w_comm2.into(),
1685 w_comm3.into(),
1686 w_comm4.into(),
1687 w_comm5.into(),
1688 w_comm6.into(),
1689 w_comm7.into(),
1690 w_comm8.into(),
1691 w_comm9.into(),
1692 w_comm10.into(),
1693 w_comm11.into(),
1694 w_comm12.into(),
1695 w_comm13.into(),
1696 w_comm14.into(),
1697 ],
1698 z_comm: caml_prover_comm.z_comm.into(),
1699 t_comm: caml_prover_comm.t_comm.into(),
1700 lookup: caml_prover_comm.lookup.map(Into::into),
1701 }
1702 }
1703 }
1704
1705 #[allow(type_alias_bounds)]
1712 type ProofTuple<const FULL_ROUNDS: usize, G: AffineRepr> = (
1713 ProverProof<G, OpeningProof<G, FULL_ROUNDS>, FULL_ROUNDS>,
1714 Vec<<G as AffineRepr>::ScalarField>,
1715 );
1716
1717 impl<const FULL_ROUNDS: usize, G, CamlG, CamlF> From<ProofTuple<FULL_ROUNDS, G>>
1718 for CamlProofWithPublic<CamlG, CamlF>
1719 where
1720 G: AffineRepr,
1721 G::BaseField: PrimeField,
1722 G: poly_commitment::commitment::EndoCurve,
1723 CamlG: From<G>,
1724 CamlF: From<G::ScalarField>,
1725 {
1726 fn from(pp: ProofTuple<FULL_ROUNDS, G>) -> Self {
1727 let (public_evals, evals) = pp.0.evals.into();
1728 CamlProofWithPublic {
1729 public_evals,
1730 proof: CamlProverProof {
1731 commitments: pp.0.commitments.into(),
1732 proof: pp.0.proof.into(),
1733 evals,
1734 ft_eval1: pp.0.ft_eval1.into(),
1735 public: pp.1.into_iter().map(Into::into).collect(),
1736 prev_challenges: pp.0.prev_challenges.into_iter().map(Into::into).collect(),
1737 },
1738 }
1739 }
1740 }
1741
1742 impl<const FULL_ROUNDS: usize, G, CamlG, CamlF> From<CamlProofWithPublic<CamlG, CamlF>>
1743 for ProofTuple<FULL_ROUNDS, G>
1744 where
1745 CamlF: Clone,
1746 G: AffineRepr + From<CamlG>,
1747 G::BaseField: PrimeField,
1748 G: poly_commitment::commitment::EndoCurve,
1749 G::ScalarField: From<CamlF>,
1750 {
1751 fn from(caml_pp: CamlProofWithPublic<CamlG, CamlF>) -> Self {
1752 let CamlProofWithPublic {
1753 public_evals,
1754 proof: caml_pp,
1755 } = caml_pp;
1756 let proof = ProverProof {
1757 commitments: caml_pp.commitments.into(),
1758 proof: caml_pp.proof.into(),
1759 evals: (public_evals, caml_pp.evals).into(),
1760 ft_eval1: caml_pp.ft_eval1.into(),
1761 prev_challenges: caml_pp
1762 .prev_challenges
1763 .into_iter()
1764 .map(Into::into)
1765 .collect(),
1766 };
1767
1768 (proof, caml_pp.public.into_iter().map(Into::into).collect())
1769 }
1770 }
1771}